use super::{Codex, StaticCodex};
use crate::Result;
pub struct DynamicCodex {
inner: StaticCodex,
}
impl core::fmt::Debug for DynamicCodex {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("DynamicCodex")
.field("table", &"<redacted>")
.finish()
}
}
impl DynamicCodex {
pub fn new() -> Result<Self> {
Ok(Self {
inner: StaticCodex::random_involution()?,
})
}
}
impl Codex for DynamicCodex {
#[inline]
fn encode(&self, byte: u8) -> u8 {
self.inner.encode(byte)
}
#[inline]
fn decode(&self, byte: u8) -> u8 {
self.inner.decode(byte)
}
}
#[cfg(test)]
#[allow(
clippy::unwrap_used,
clippy::expect_used,
clippy::cast_possible_truncation,
clippy::cast_sign_loss
)]
mod tests {
use super::*;
#[test]
fn involution_holds_for_every_byte() {
let codex = DynamicCodex::new().unwrap();
for byte in 0u8..=255 {
assert_eq!(codex.decode(codex.encode(byte)), byte);
}
}
#[test]
fn no_fixed_points() {
let codex = DynamicCodex::new().unwrap();
for byte in 0u8..=255 {
assert_ne!(codex.encode(byte), byte);
}
}
#[test]
fn two_instances_have_different_tables() {
let a = DynamicCodex::new().unwrap();
let b = DynamicCodex::new().unwrap();
let any_diff = (0u8..=255).any(|b_in| a.encode(b_in) != b.encode(b_in));
assert!(
any_diff,
"two random codices encoded identically — broken RNG?"
);
}
}