use crate::{
Error,
bits::{
NBits, Unary, VarNBits,
bitvec::{order::Msb0, slice::BitSlice, vec::BitVec},
de::{BitReader, BitReaderExt, BitUnpackAs},
ser::{BitPackAs, BitWriter, BitWriterExt},
},
};
pub struct HmLabel;
impl BitPackAs<BitSlice<u8, Msb0>> for HmLabel {
type Args = u32;
fn pack_as<W>(
source: &BitSlice<u8, Msb0>,
writer: &mut W,
m: Self::Args,
) -> Result<(), W::Error>
where
W: BitWriter + ?Sized,
{
let n = source.len() as u32;
if n < m {
writer
.pack(false, ())?
.pack_as::<_, Unary>(source.len(), ())?
.write_bitslice(source)?;
return Ok(());
}
let n_bits = m.ilog2() + 1;
let v = if source.all() {
true
} else if source.not_any() {
false
} else {
writer
.pack_as::<_, NBits<2>>(0b10, ())?
.pack_as::<_, VarNBits>(n, n_bits)?
.write_bitslice(source)?;
return Ok(());
};
writer
.pack_as::<_, NBits<2>>(0b11, ())?
.pack(v, ())?
.pack_as::<_, VarNBits>(n, n_bits)?;
Ok(())
}
}
impl<'de> BitUnpackAs<'de, BitVec<u8, Msb0>> for HmLabel {
type Args = u32;
fn unpack_as<R>(reader: &mut R, m: Self::Args) -> Result<BitVec<u8, Msb0>, R::Error>
where
R: BitReader<'de> + ?Sized,
{
match reader.unpack(())? {
false => {
let n: u32 = reader.unpack_as::<_, Unary>(())?;
if n > m {
return Err(Error::custom("n > m"));
}
reader.unpack(n as usize)
}
true => match reader.unpack(())? {
false => {
let n: u32 = reader.unpack_as::<_, VarNBits>(m.ilog2() + 1)?;
reader.unpack(n as usize)
}
true => {
let v: bool = reader.unpack(())?;
let n: u32 = reader.unpack_as::<_, VarNBits>(m.ilog2() + 1)?;
Ok(BitVec::repeat(v, n as usize))
}
},
}
}
}