#![warn(missing_docs)]
pub trait FromBits {
type Symbol;
fn from_bits<F, E>(next: F) -> Result<Self::Symbol, E>
where
F: FnMut() -> Result<bool, E>;
}
pub trait ToBits {
type Symbol;
fn to_bits<F, E>(value: Self::Symbol, write: F) -> Result<(), E>
where
F: FnMut(bool) -> Result<(), E>;
}
#[macro_export]
macro_rules! define_huffman_tree {
($name:ident : $type:ty = $nodes:tt) => {
#[derive(Copy, Clone, Debug)]
struct $name;
impl $crate::huffman::FromBits for $name {
type Symbol = $type;
fn from_bits<F, E>(mut next: F) -> Result<Self::Symbol, E>
where
F: FnMut() -> Result<bool, E>,
{
$crate::compile_read_tree_nodes!(next, $nodes)
}
}
impl $crate::huffman::ToBits for $name {
type Symbol = $type;
fn to_bits<F, E>(value: Self::Symbol, mut write: F) -> Result<(), E>
where
F: FnMut(bool) -> Result<(), E>
{
$crate::compile_write_tree_nodes!(value ; write ; $nodes ; );
Ok(())
}
}
};
}
#[macro_export]
macro_rules! compile_read_tree_nodes {
($next:ident , [$bit_0:tt, $bit_1:tt]) => {
if $next()? {
$crate::compile_read_tree_nodes!($next, $bit_1)
} else {
$crate::compile_read_tree_nodes!($next, $bit_0)
}
};
($next:ident , $final:tt) => {
Ok($final)
};
}
#[macro_export]
macro_rules! compile_write_tree_nodes {
($final:tt) => {
1
};
([$bit_0:tt, $bit_1:tt]) => {
compile_write_tree_nodes!($bit_0) + compile_write_tree_nodes!($bit_1)
};
($value:ident ; $write:ident ; [$bit_0:tt, $bit_1:tt] ; ) => {
if $crate::compile_write_tree_nodes!($bit_0) <= $crate::compile_write_tree_nodes!($bit_1) {
$crate::compile_write_tree_nodes!($value ; $write ; $bit_0 ; false);
$crate::compile_write_tree_nodes!($value ; $write ; $bit_1 ; true);
} else {
$crate::compile_write_tree_nodes!($value ; $write ; $bit_1 ; false);
$crate::compile_write_tree_nodes!($value ; $write ; $bit_0 ; true);
}
};
($value:ident ; $write:ident ; [$bit_0:tt, $bit_1:tt] ; $($bits:tt),*) => {
if $crate::compile_write_tree_nodes!($bit_0) <= $crate::compile_write_tree_nodes!($bit_1) {
$crate::compile_write_tree_nodes!($value ; $write ; $bit_0 ; $($bits),* , false);
$crate::compile_write_tree_nodes!($value ; $write ; $bit_1 ; $($bits),* , true);
} else {
$crate::compile_write_tree_nodes!($value ; $write ; $bit_1 ; $($bits),* , false);
$crate::compile_write_tree_nodes!($value ; $write ; $bit_0 ; $($bits),* , true);
}
};
($value:ident ; $write:ident ; $final:tt ; $( $bits:tt),* ) => {
if $value == $final {
$( $write($bits)?; )*
return Ok(());
}
};
}
#[derive(Copy, Clone, Debug)]
pub struct LimitedUnary<const STOP_BIT: u8, const MAXIMUM: u32>;
impl<const STOP_BIT: u8, const MAXIMUM: u32> FromBits for LimitedUnary<STOP_BIT, MAXIMUM> {
type Symbol = Option<u32>;
fn from_bits<F, E>(mut next: F) -> Result<Self::Symbol, E>
where
F: FnMut() -> Result<bool, E>,
{
const {
assert!(matches!(STOP_BIT, 0 | 1), "stop bit must be 0 or 1");
}
let mut bits = 0;
while bits < MAXIMUM {
if next()?
!= match STOP_BIT {
0 => false,
1 => true,
_ => unreachable!(),
}
{
bits += 1;
} else {
return Ok(Some(bits));
}
}
Ok(None)
}
}
impl<const STOP_BIT: u8, const MAXIMUM: u32> ToBits for LimitedUnary<STOP_BIT, MAXIMUM> {
type Symbol = Option<u32>;
fn to_bits<F, E>(value: Option<u32>, mut write: F) -> Result<(), E>
where
F: FnMut(bool) -> Result<(), E>,
{
const {
assert!(matches!(STOP_BIT, 0 | 1), "stop bit must be 0 or 1");
}
match value {
Some(bits) if bits < MAXIMUM => {
(0..bits).try_for_each(|_| {
write(match STOP_BIT {
0 => true,
1 => false,
_ => unreachable!(),
})
})?;
write(match STOP_BIT {
0 => false,
1 => true,
_ => unreachable!(),
})
}
Some(_) => {
Ok(())
}
None => (0..MAXIMUM).try_for_each(|_| {
write(match STOP_BIT {
0 => true,
1 => false,
_ => unreachable!(),
})
}),
}
}
}