libribzip2 0.5.0

a bzip2 library written in pure rust
Documentation
use crate::{
    bitwise::{
        bitreader::BitReader,
        bitwriter::{convert_to_code_pad_to_n_bits, convert_to_number},
    },
    {bitwise::Bit, block::delta::DeltaSymbol},
};

use super::{
    delta::{encode_delta, DeltaEncoded},
    huffman::CanonicalCodeTable,
};

pub(crate) fn encode_code_table<T>(table: CanonicalCodeTable<T>) -> Vec<Bit> {
    let code_lengths = table
        .0
        .iter()
        .map(|entry| entry.code.len() as u8)
        .collect::<Vec<_>>();
    encode_bit_lengths(&code_lengths)
}

fn encode_bit_lengths(code_lengths: &[u8]) -> Vec<Bit> {
    let mut out = Vec::<Bit>::new();

    let delta = encode_delta(code_lengths.to_vec());
    match delta {
        DeltaEncoded::Empty => {}
        DeltaEncoded::NonEmpty(enc) => {
            out.append(&mut convert_to_code_pad_to_n_bits(
                enc.start_value as usize,
                5,
            ));
            out.append(
                &mut enc
                    .deltas
                    .iter()
                    .flat_map(|d| match d {
                        DeltaSymbol::Decrease => {
                            vec![Bit::One, Bit::One]
                        }
                        DeltaSymbol::Increase => {
                            vec![Bit::One, Bit::Zero]
                        }
                        DeltaSymbol::Stop => vec![Bit::Zero],
                    })
                    .collect::<Vec<Bit>>(),
            );
        }
    }
    out
}

pub(crate) trait ReadDelta {
    fn read_delta(&mut self, amount: usize) -> Result<Vec<u8>, ()>;
}

impl<T> ReadDelta for T
where
    T: BitReader,
{
    fn read_delta(&mut self, amount: usize) -> Result<Vec<u8>, ()> {
        let mut out = vec![];
        let mut read = 0;

        let mut start = convert_to_number(&self.read_bits(5)?);
        loop {
            match &self.read_bits(1)?[..] {
                [Bit::One] => match &self.read_bits(1)?[..] {
                    [Bit::Zero] => start += 1,
                    _ => start -= 1,
                },
                _ => {
                    out.push(start as u8);
                    read += 1;
                }
            }
            if read == amount {
                break;
            }
        }
        Ok(out)
    }
}

#[cfg(test)]
mod test {
    use std::io::Cursor;

    use crate::bitwise::{
        bitreader::BitReaderImpl,
        bitwriter::{BitWriter, BitWriterImpl},
    };

    use super::*;

    #[test]
    pub fn reads_table() {
        let lengths = vec![1, 2, 3, 4];
        let mut buf = vec![];
        {
            let mut writer = BitWriterImpl::from_writer(&mut buf);
            writer.write_bits(&encode_bit_lengths(&lengths)).unwrap();
            writer.finalize().unwrap();
        }
        let mut cursor = Cursor::new(&buf);
        let mut bit_reader = BitReaderImpl::from_reader(&mut cursor);
        let read = bit_reader.read_delta(4);

        assert_eq!(lengths, read.unwrap());
    }
}