#![allow(clippy::type_complexity)]
pub mod exp_golomb;
pub mod huffman;
use alloc::vec::Vec;
use core::{
borrow::Borrow,
convert::Infallible,
fmt::{Debug, Display},
iter::{Repeat, Take},
marker::PhantomData,
ops::Deref,
};
use smallvec::SmallVec;
use crate::{
backends::{AsReadWords, BoundedReadWords, Cursor, IntoReadWords, ReadWords, WriteWords},
BitArray, CoderError, DefaultEncoderError, Queue, Semantics, Stack, UnwrapInfallible,
};
pub trait ReadBitStream<S: Semantics> {
type ReadError;
fn read_bit(&mut self) -> Result<Option<bool>, Self::ReadError>;
fn decode_symbol<C: DecoderCodebook>(
&mut self,
codebook: C,
) -> Result<C::Symbol, CoderError<SymbolCodeError<C::InvalidCodeword>, Self::ReadError>>;
fn decode_symbols<'s, I, C>(&'s mut self, codebooks: I) -> DecodeSymbols<'s, Self, I, S>
where
I: IntoIterator<Item = C> + 's,
C: DecoderCodebook,
{
DecodeSymbols {
bit_stream: self,
codebooks,
semantics: PhantomData,
}
}
fn decode_iid_symbols<'a, C>(
&'a mut self,
amt: usize,
codebook: &'a C,
) -> DecodeSymbols<'a, Self, Take<Repeat<&'a C>>, S>
where
C: DecoderCodebook,
{
self.decode_symbols(core::iter::repeat(codebook).take(amt))
}
}
pub trait WriteBitStream<S: Semantics> {
type WriteError;
fn write_bit(&mut self, bit: bool) -> Result<(), Self::WriteError>;
fn encode_symbol<Symbol, C>(
&mut self,
symbol: Symbol,
codebook: C,
) -> Result<(), DefaultEncoderError<Self::WriteError>>
where
C: EncoderCodebook,
Symbol: Borrow<C::Symbol>;
fn encode_symbols<Symbol, C>(
&mut self,
symbols_and_codebooks: impl IntoIterator<Item = (Symbol, C)>,
) -> Result<(), DefaultEncoderError<Self::WriteError>>
where
C: EncoderCodebook,
Symbol: Borrow<C::Symbol>,
{
for (symbol, codebook) in symbols_and_codebooks.into_iter() {
self.encode_symbol(symbol, codebook)?;
}
Ok(())
}
fn encode_iid_symbols<Symbol, C>(
&mut self,
symbols: impl IntoIterator<Item = Symbol>,
codebook: &C,
) -> Result<(), DefaultEncoderError<Self::WriteError>>
where
C: EncoderCodebook,
Symbol: Borrow<C::Symbol>,
{
self.encode_symbols(symbols.into_iter().map(|symbol| (symbol, codebook)))
}
}
#[derive(Debug)]
pub struct DecodeSymbols<'a, Stream: ?Sized, I, S: Semantics> {
bit_stream: &'a mut Stream,
codebooks: I,
semantics: PhantomData<S>,
}
impl<'a, Stream, I, C, S> Iterator for DecodeSymbols<'a, Stream, I, S>
where
S: Semantics,
Stream: ReadBitStream<S>,
C: DecoderCodebook,
I: Iterator<Item = C>,
{
type Item =
Result<C::Symbol, CoderError<SymbolCodeError<C::InvalidCodeword>, Stream::ReadError>>;
#[inline(always)]
fn next(&mut self) -> Option<Self::Item> {
Some(self.bit_stream.decode_symbol(self.codebooks.next()?))
}
#[inline(always)]
fn size_hint(&self) -> (usize, Option<usize>) {
self.codebooks.size_hint()
}
}
impl<'a, Stream, I, C, S> ExactSizeIterator for DecodeSymbols<'a, Stream, I, S>
where
S: Semantics,
Stream: ReadBitStream<S>,
C: DecoderCodebook,
I: ExactSizeIterator<Item = C>,
{
}
#[derive(Clone, PartialEq, Eq, Debug, Default)]
pub struct SymbolCoder<Word: BitArray, S: Semantics, B = Vec<Word>> {
backend: B,
current_word: Word,
mask_last_written: Word,
semantics: PhantomData<S>,
}
pub type QueueEncoder<Word, B = Vec<Word>> = SymbolCoder<Word, Queue, B>;
pub type StackCoder<Word, B = Vec<Word>> = SymbolCoder<Word, Stack, B>;
#[derive(Clone, PartialEq, Eq, Debug, Default)]
pub struct QueueDecoder<Word: BitArray, B> {
backend: B,
current_word: Word,
mask_next_to_read: Word,
}
pub type DefaultQueueEncoder = QueueEncoder<u32, Vec<u32>>;
pub type DefaultQueueDecoder = QueueDecoder<u32, Cursor<u32, Vec<u32>>>;
pub type DefaultStackCoder = StackCoder<u32, Vec<u32>>;
impl<Word: BitArray, S: Semantics, B> SymbolCoder<Word, S, B> {
pub fn new() -> Self
where
B: Default,
{
Default::default()
}
pub fn len(&self) -> usize
where
B: BoundedReadWords<Word, Stack>,
{
self.backend
.remaining()
.checked_mul(Word::BITS)
.expect("len overflows addressable space")
.checked_add(if self.mask_last_written == Word::zero() {
0
} else {
(self.mask_last_written.trailing_zeros() + 1) as usize
})
.expect("len overflows addressable space")
}
pub fn is_empty(&self) -> bool
where
B: BoundedReadWords<Word, Stack>,
{
self.mask_last_written == Word::zero() && self.backend.is_exhausted()
}
}
impl<Word: BitArray> StackCoder<Word, Vec<Word>> {
pub fn with_bit_capacity(bit_capacity: usize) -> Self {
Self {
backend: Vec::with_capacity(bit_capacity / Word::BITS + 1),
..Default::default()
}
}
pub fn get_compressed(&mut self) -> StackCoderGuard<'_, Word> {
StackCoderGuard::new(self)
}
}
impl<Word: BitArray> QueueEncoder<Word, Vec<Word>> {
pub fn with_bit_capacity(bit_capacity: usize) -> Self {
Self {
backend: Vec::with_capacity((bit_capacity + Word::BITS - 1) / Word::BITS),
..Default::default()
}
}
pub fn get_compressed(&mut self) -> QueueEncoderGuard<'_, Word> {
QueueEncoderGuard::new(self)
}
}
#[derive(Debug)]
pub struct StackCoderGuard<'a, Word: BitArray> {
inner: &'a mut StackCoder<Word, Vec<Word>>,
}
impl<'a, Word: BitArray> StackCoderGuard<'a, Word> {
fn new(stack_coder: &'a mut StackCoder<Word, Vec<Word>>) -> Self {
stack_coder.write_bit(true).unwrap_infallible();
if stack_coder.mask_last_written != Word::zero() {
stack_coder.backend.push(stack_coder.current_word);
}
Self { inner: stack_coder }
}
}
impl<'a, Word: BitArray> Drop for StackCoderGuard<'a, Word> {
fn drop(&mut self) {
if self.inner.mask_last_written != Word::zero() {
self.inner.backend.pop();
}
self.inner.read_bit().expect("The constructor wrote a bit.");
}
}
impl<'a, Word: BitArray> Deref for StackCoderGuard<'a, Word> {
type Target = [Word];
fn deref(&self) -> &Self::Target {
&self.inner.backend
}
}
#[derive(Debug)]
pub struct QueueEncoderGuard<'a, Word: BitArray> {
inner: &'a mut QueueEncoder<Word, Vec<Word>>,
}
impl<'a, Word: BitArray> QueueEncoderGuard<'a, Word> {
fn new(queue_encoder: &'a mut QueueEncoder<Word, Vec<Word>>) -> Self {
if queue_encoder.mask_last_written != Word::zero() {
queue_encoder.backend.push(queue_encoder.current_word);
}
Self {
inner: queue_encoder,
}
}
}
impl<'a, Word: BitArray> Drop for QueueEncoderGuard<'a, Word> {
fn drop(&mut self) {
if self.inner.mask_last_written != Word::zero() {
self.inner.backend.pop();
}
}
}
impl<'a, Word: BitArray> Deref for QueueEncoderGuard<'a, Word> {
type Target = [Word];
fn deref(&self) -> &Self::Target {
&self.inner.backend
}
}
impl<Word: BitArray, B> QueueEncoder<Word, B> {
pub fn from_compressed(compressed: B) -> Self
where
B: Default,
{
Self {
backend: compressed,
..Default::default()
}
}
pub fn into_decoder(self) -> Result<QueueDecoder<Word, B::IntoReadWords>, B::WriteError>
where
B: WriteWords<Word> + IntoReadWords<Word, Queue>,
{
Ok(QueueDecoder::from_compressed(
self.into_compressed()?.into_read_words(),
))
}
pub fn into_compressed(mut self) -> Result<B, B::WriteError>
where
B: WriteWords<Word>,
{
if self.mask_last_written != Word::zero() {
self.backend.write(self.current_word)?;
}
Ok(self.backend)
}
pub fn into_overshooting_iter(
self,
) -> Result<
impl Iterator<Item = Result<bool, <B::IntoReadWords as ReadWords<Word, Queue>>::ReadError>>,
B::WriteError,
>
where
B: WriteWords<Word> + IntoReadWords<Word, Queue>,
{
self.into_decoder()
}
}
impl<Word: BitArray, B: WriteWords<Word>> WriteBitStream<Queue> for QueueEncoder<Word, B> {
type WriteError = B::WriteError;
fn write_bit(&mut self, bit: bool) -> Result<(), Self::WriteError> {
let write_mask = self.mask_last_written << 1;
self.mask_last_written = if write_mask != Word::zero() {
let new_bit = if bit { write_mask } else { Word::zero() };
self.current_word = self.current_word | new_bit;
write_mask
} else {
if self.mask_last_written != Word::zero() {
self.backend.write(self.current_word)?;
}
self.current_word = if bit { Word::one() } else { Word::zero() };
Word::one()
};
Ok(())
}
#[inline(always)]
fn encode_symbol<Symbol, C>(
&mut self,
symbol: Symbol,
codebook: C,
) -> Result<(), DefaultEncoderError<Self::WriteError>>
where
C: EncoderCodebook,
Symbol: Borrow<C::Symbol>,
{
codebook.encode_symbol_prefix(symbol, |bit| self.write_bit(bit))
}
}
impl<Word: BitArray, B> QueueDecoder<Word, B> {
pub fn from_compressed(compressed: B) -> Self {
Self {
backend: compressed,
current_word: Word::zero(),
mask_next_to_read: Word::zero(),
}
}
pub fn maybe_exhausted(&self) -> bool
where
B: BoundedReadWords<Word, Queue>,
{
let mask_remaining_bits = !self.mask_next_to_read.wrapping_sub(&Word::one());
self.current_word & mask_remaining_bits == Word::zero() && self.backend.is_exhausted()
}
}
impl<Word: BitArray, B: ReadWords<Word, Queue>> ReadBitStream<Queue> for QueueDecoder<Word, B> {
type ReadError = B::ReadError;
#[inline(always)]
fn decode_symbol<C: DecoderCodebook>(
&mut self,
codebook: C,
) -> Result<C::Symbol, CoderError<SymbolCodeError<C::InvalidCodeword>, Self::ReadError>> {
codebook.decode_symbol(self)
}
fn read_bit(&mut self) -> Result<Option<bool>, Self::ReadError> {
if self.mask_next_to_read == Word::zero() {
match self.backend.read() {
Ok(Some(next_word)) => {
self.current_word = next_word;
self.mask_next_to_read = Word::one();
}
Ok(None) => return Ok(None),
Err(err) => return Err(err),
}
}
let bit = self.current_word & self.mask_next_to_read != Word::zero();
self.mask_next_to_read = self.mask_next_to_read << 1;
Ok(Some(bit))
}
}
impl<Word: BitArray, B: ReadWords<Word, Queue>> Iterator for QueueDecoder<Word, B> {
type Item = Result<bool, B::ReadError>;
fn next(&mut self) -> Option<Self::Item> {
self.read_bit().transpose()
}
}
impl<Word: BitArray, B: WriteWords<Word>> StackCoder<Word, B> {
pub fn from_compressed(mut compressed: B) -> Result<Self, CoderError<B, B::ReadError>>
where
B: ReadWords<Word, Stack>,
{
let (current_word, mask_last_written) = if let Some(last_word) = compressed.read()? {
if last_word == Word::zero() {
return Err(CoderError::Frontend(compressed));
}
let mask_end_bit = Word::one() << last_word.trailing_zeros() as usize;
(last_word ^ mask_end_bit, mask_end_bit >> 1)
} else {
(Word::zero(), Word::zero())
};
Ok(Self {
backend: compressed,
current_word,
mask_last_written,
semantics: PhantomData,
})
}
pub fn into_compressed(mut self) -> Result<B, B::WriteError> {
self.write_bit(true)?;
if self.mask_last_written != Word::zero() {
self.backend.write(self.current_word)?;
}
Ok(self.backend)
}
#[inline(always)]
pub fn encode_symbols_reverse<Symbol, C, I>(
&mut self,
symbols_and_codebooks: I,
) -> Result<(), DefaultEncoderError<B::WriteError>>
where
Symbol: Borrow<C::Symbol>,
C: EncoderCodebook,
I: IntoIterator<Item = (Symbol, C)>,
I::IntoIter: DoubleEndedIterator,
{
self.encode_symbols(symbols_and_codebooks.into_iter().rev())
}
#[inline(always)]
pub fn encode_iid_symbols_reverse<Symbol, C, I>(
&mut self,
symbols: I,
codebook: &C,
) -> Result<(), DefaultEncoderError<B::WriteError>>
where
Symbol: Borrow<C::Symbol>,
C: EncoderCodebook,
I: IntoIterator<Item = Symbol>,
I::IntoIter: DoubleEndedIterator,
{
self.encode_iid_symbols(symbols.into_iter().rev(), codebook)
}
pub fn into_decoder(self) -> SymbolCoder<Word, Stack, B::IntoReadWords>
where
B: IntoReadWords<Word, Stack>,
{
SymbolCoder {
backend: self.backend.into_read_words(),
current_word: self.current_word,
mask_last_written: self.mask_last_written,
semantics: PhantomData,
}
}
pub fn as_decoder<'a>(&'a self) -> SymbolCoder<Word, Stack, B::AsReadWords>
where
B: AsReadWords<'a, Word, Stack>,
{
SymbolCoder {
backend: self.backend.as_read_words(),
current_word: self.current_word,
mask_last_written: self.mask_last_written,
semantics: PhantomData,
}
}
pub fn into_iterator(
self,
) -> impl Iterator<Item = Result<bool, <B::IntoReadWords as ReadWords<Word, Stack>>::ReadError>>
where
B: IntoReadWords<Word, Stack>,
{
self.into_decoder()
}
pub fn iter<'a>(
&'a self,
) -> impl Iterator<
Item = Result<
bool,
<<B as AsReadWords<'a, Word, Stack>>::AsReadWords as ReadWords<Word, Stack>>::ReadError,
>,
> + 'a
where
B: AsReadWords<'a, Word, Stack>,
{
self.as_decoder()
}
}
impl<Word: BitArray, B: WriteWords<Word>> WriteBitStream<Stack> for StackCoder<Word, B> {
type WriteError = B::WriteError;
fn write_bit(&mut self, bit: bool) -> Result<(), Self::WriteError> {
let write_mask = self.mask_last_written << 1;
self.mask_last_written = if write_mask != Word::zero() {
let new_bit = if bit { write_mask } else { Word::zero() };
self.current_word = self.current_word | new_bit;
write_mask
} else {
if self.mask_last_written != Word::zero() {
self.backend.write(self.current_word)?;
}
self.current_word = if bit { Word::one() } else { Word::zero() };
Word::one()
};
Ok(())
}
#[inline(always)]
fn encode_symbol<Symbol, C>(
&mut self,
symbol: Symbol,
codebook: C,
) -> Result<(), DefaultEncoderError<Self::WriteError>>
where
Symbol: Borrow<C::Symbol>,
C: EncoderCodebook,
{
codebook.encode_symbol_suffix(symbol, |bit| self.write_bit(bit))
}
}
impl<Word: BitArray, B: ReadWords<Word, Stack>> ReadBitStream<Stack> for StackCoder<Word, B> {
type ReadError = B::ReadError;
#[inline(always)]
fn decode_symbol<C: DecoderCodebook>(
&mut self,
codebook: C,
) -> Result<C::Symbol, CoderError<SymbolCodeError<C::InvalidCodeword>, Self::ReadError>> {
codebook.decode_symbol(self)
}
fn read_bit(&mut self) -> Result<Option<bool>, Self::ReadError> {
if self.mask_last_written == Word::zero() {
self.current_word = if let Some(next_word) = self.backend.read()? {
next_word
} else {
return Ok(None);
};
self.mask_last_written = Word::one() << (Word::BITS - 1);
}
let bit = self.current_word & self.mask_last_written;
self.current_word = self.current_word ^ bit;
self.mask_last_written = self.mask_last_written >> 1;
Ok(Some(bit != Word::zero()))
}
}
impl<Word: BitArray, B: ReadWords<Word, Stack>> Iterator for StackCoder<Word, B> {
type Item = Result<bool, B::ReadError>;
fn next(&mut self) -> Option<Self::Item> {
self.read_bit().transpose()
}
}
impl<Word: BitArray, B: BoundedReadWords<Word, Stack>> ExactSizeIterator for StackCoder<Word, B> {
fn len(&self) -> usize {
StackCoder::len(self)
}
}
type SmallBitStack = StackCoder<usize, SmallVec<[usize; 1]>>;
#[derive(Debug)]
pub enum SymbolCodeError<InvalidCodeword = Infallible> {
OutOfCompressedData,
InvalidCodeword(InvalidCodeword),
}
impl<InvalidCodeword> SymbolCodeError<InvalidCodeword> {
pub fn into_coder_error<BackendError>(self) -> CoderError<Self, BackendError> {
CoderError::Frontend(self)
}
}
impl<InvalidCodeword: Display> Display for SymbolCodeError<InvalidCodeword> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::OutOfCompressedData => write!(
f,
"The compressed data ended before the current codeword was complete."
),
Self::InvalidCodeword(err) => write!(f, "Invalid codeword for this codebook: {err}"),
}
}
}
#[cfg(feature = "std")]
impl<InvalidCodeword: std::error::Error + 'static> std::error::Error
for SymbolCodeError<InvalidCodeword>
{
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::OutOfCompressedData => None,
Self::InvalidCodeword(source) => Some(source),
}
}
}
pub trait Codebook {
type Symbol;
}
pub trait EncoderCodebook: Codebook {
fn encode_symbol_prefix<BackendError>(
&self,
symbol: impl Borrow<Self::Symbol>,
mut emit: impl FnMut(bool) -> Result<(), BackendError>,
) -> Result<(), DefaultEncoderError<BackendError>> {
let mut reverse_codeword = SmallBitStack::new();
self.encode_symbol_suffix(symbol, |bit| reverse_codeword.write_bit(bit))
.map_err(|err| CoderError::Frontend(err.into_frontend_error()))?;
for bit in reverse_codeword {
emit(bit.unwrap_infallible())?;
}
Ok(())
}
fn encode_symbol_suffix<BackendError>(
&self,
symbol: impl Borrow<Self::Symbol>,
mut emit: impl FnMut(bool) -> Result<(), BackendError>,
) -> Result<(), DefaultEncoderError<BackendError>> {
let mut reverse_codeword = SmallBitStack::new();
self.encode_symbol_prefix(symbol, |bit| reverse_codeword.write_bit(bit))
.map_err(|err| CoderError::Frontend(err.into_frontend_error()))?;
for bit in reverse_codeword {
emit(bit.unwrap_infallible())?;
}
Ok(())
}
}
pub trait DecoderCodebook: Codebook {
type InvalidCodeword;
fn decode_symbol<BackendError>(
&self,
source: impl Iterator<Item = Result<bool, BackendError>>,
) -> Result<Self::Symbol, CoderError<SymbolCodeError<Self::InvalidCodeword>, BackendError>>;
}
impl<C: Codebook> Codebook for &C {
type Symbol = C::Symbol;
}
impl<C: EncoderCodebook> EncoderCodebook for &C {
#[inline(always)]
fn encode_symbol_prefix<BackendError>(
&self,
symbol: impl Borrow<Self::Symbol>,
emit: impl FnMut(bool) -> Result<(), BackendError>,
) -> Result<(), DefaultEncoderError<BackendError>> {
(*self).encode_symbol_prefix(symbol, emit)
}
#[inline(always)]
fn encode_symbol_suffix<BackendError>(
&self,
symbol: impl Borrow<Self::Symbol>,
emit: impl FnMut(bool) -> Result<(), BackendError>,
) -> Result<(), DefaultEncoderError<BackendError>> {
(*self).encode_symbol_suffix(symbol, emit)
}
}
impl<C: DecoderCodebook> DecoderCodebook for &C {
type InvalidCodeword = C::InvalidCodeword;
fn decode_symbol<BackendError>(
&self,
source: impl Iterator<Item = Result<bool, BackendError>>,
) -> Result<Self::Symbol, CoderError<SymbolCodeError<Self::InvalidCodeword>, BackendError>>
{
(*self).decode_symbol(source)
}
}
#[cfg(test)]
mod tests {
use super::{
huffman::{DecoderHuffmanTree, EncoderHuffmanTree},
*,
};
use crate::UnwrapInfallible;
use rand_xoshiro::{
rand_core::{RngCore, SeedableRng},
Xoshiro256StarStar,
};
#[test]
fn bit_queue() {
let mut bit_queue = DefaultQueueEncoder::new();
assert_eq!(bit_queue.len(), 0);
assert!(bit_queue.is_empty());
let amt = 150;
let mut bool_vec = Vec::with_capacity(amt);
let mut rng = Xoshiro256StarStar::seed_from_u64(123);
for _ in 0..amt {
let bit = rng.next_u32() % 2 != 0;
bit_queue.write_bit(bit).unwrap();
bool_vec.push(bit);
}
assert_eq!(bit_queue.len(), amt);
assert!(!bit_queue.is_empty());
let mut queue_iter = bit_queue.into_overshooting_iter().unwrap_infallible();
for expected in bool_vec {
assert_eq!(queue_iter.next().unwrap().unwrap_infallible(), expected);
}
for remaining in queue_iter {
assert!(!remaining.unwrap_infallible());
}
}
#[test]
fn bit_stack() {
let mut bit_stack = DefaultStackCoder::new();
assert_eq!(bit_stack.len(), 0);
assert!(bit_stack.is_empty());
let amt = 150;
let mut bool_vec = Vec::with_capacity(amt);
let mut rng = Xoshiro256StarStar::seed_from_u64(123);
for _ in 0..amt {
let bit = rng.next_u32() % 2 != 0;
bit_stack.write_bit(bit).unwrap();
bool_vec.push(bit);
}
assert_eq!(bit_stack.len(), amt);
assert!(!bit_stack.is_empty());
assert!(bool_vec.into_iter().rev().eq(bit_stack.map(Result::unwrap)));
}
#[test]
fn encode_decode_iid_queue() {
let amt = 1000;
let mut rng = Xoshiro256StarStar::seed_from_u64(12345);
let symbols = (0..amt)
.map(|_| (rng.next_u32() % 5) as usize)
.collect::<Vec<_>>();
let probabilities = [2, 2, 4, 1, 1];
let encoder_codebook = EncoderHuffmanTree::from_probabilities::<u32, _>(&probabilities);
let decoder_codebook = DecoderHuffmanTree::from_probabilities::<u32, _>(&probabilities);
let mut encoder = DefaultQueueEncoder::new();
assert_eq!(encoder.len(), 0);
encoder
.encode_iid_symbols(&symbols, &encoder_codebook)
.unwrap();
assert!(encoder.len() > amt);
let mut decoder = encoder.into_decoder().unwrap_infallible();
let reconstructed = decoder
.decode_iid_symbols(amt, &decoder_codebook)
.collect::<Result<Vec<_>, _>>()
.unwrap();
assert_eq!(reconstructed, symbols);
assert!(decoder.maybe_exhausted());
}
#[test]
fn encode_decode_iid_stack() {
let amt = 1000;
let mut rng = Xoshiro256StarStar::seed_from_u64(12345);
let symbols = (0..amt)
.map(|_| (rng.next_u32() % 5) as usize)
.collect::<Vec<_>>();
let probabilities = [2, 2, 4, 1, 1];
let encoder_codebook = EncoderHuffmanTree::from_probabilities::<u32, _>(&probabilities);
let decoder_codebook = DecoderHuffmanTree::from_probabilities::<u32, _>(&probabilities);
let mut coder = DefaultStackCoder::new();
assert_eq!(coder.len(), 0);
coder
.encode_iid_symbols_reverse(&symbols, &encoder_codebook)
.unwrap();
assert!(coder.len() > amt);
let reconstructed = coder
.decode_iid_symbols(amt, &decoder_codebook)
.collect::<Result<Vec<_>, _>>()
.unwrap();
assert_eq!(reconstructed, symbols);
assert!(coder.is_empty());
}
#[test]
fn encode_decode_non_iid() {
fn iter_probs_and_symbols(amt: usize) -> impl Iterator<Item = (Vec<u32>, usize)> {
let mut rng = Xoshiro256StarStar::seed_from_u64(123456);
(0..amt).map(move |_| {
let num_symbols = 1 + rng.next_u32() % 10;
let probs = (0..num_symbols).map(|_| rng.next_u32() >> 16).collect();
let symbol = rng.next_u32() % num_symbols;
(probs, symbol as usize)
})
}
#[cfg(not(miri))]
let amt = 1000;
#[cfg(miri)]
let amt = 100;
let mut compressed = DefaultQueueEncoder::new();
assert_eq!(compressed.len(), 0);
compressed
.encode_symbols(iter_probs_and_symbols(amt).map(|(probs, symbol)| {
(
symbol,
EncoderHuffmanTree::from_probabilities::<u32, _>(&probs),
)
}))
.unwrap();
assert!(compressed.len() > amt);
let mut decoder = compressed.into_decoder().unwrap_infallible();
let reconstructed = decoder
.decode_symbols(
iter_probs_and_symbols(amt)
.map(|(probs, _)| DecoderHuffmanTree::from_probabilities::<u32, _>(&probs)),
)
.map(Result::unwrap);
assert!(reconstructed.eq(iter_probs_and_symbols(amt).map(|(_, symbol)| symbol)));
assert!(decoder.maybe_exhausted());
}
}