arcode 0.2.4

An Arithmetic Coder (lossless entropy encoder)
Documentation
use std::io::Cursor;

use arcode::{ArithmeticDecoder, ArithmeticEncoder, EOFKind, Model};
use bitbit::{BitReader, BitWriter, MSB};
use byte_unit::Byte;
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};

mod sherlock;

fn encode(data: &[u8]) {
    let mut model = Model::builder().num_bits(8).eof(EOFKind::EndAddOne).build();

    let compressed = Cursor::new(vec![]);
    let mut compressed_writer = BitWriter::new(compressed);

    let mut encoder = ArithmeticEncoder::new(48);

    for &sym in data {
        encoder
            .encode(sym.into(), &model, &mut compressed_writer)
            .unwrap();
        model.update_symbol(sym.into());
    }
    encoder
        .encode(model.eof(), &model, &mut compressed_writer)
        .unwrap();
    encoder.finish_encode(&mut compressed_writer).unwrap();
}

fn encode_return(data: &[u8]) -> Vec<u8> {
    let mut model = Model::builder().num_bits(8).eof(EOFKind::EndAddOne).build();

    let compressed = Cursor::new(vec![]);
    let mut compressed_writer = BitWriter::new(compressed);

    let mut encoder = ArithmeticEncoder::new(48);

    for &sym in data {
        encoder
            .encode(sym.into(), &model, &mut compressed_writer)
            .unwrap();
        model.update_symbol(sym.into());
    }
    encoder
        .encode(model.eof(), &model, &mut compressed_writer)
        .unwrap();
    encoder.finish_encode(&mut compressed_writer).unwrap();

    compressed_writer.get_ref().get_ref().clone()
}

fn decode(data: &[u8]) {
    let mut model = Model::builder().num_bits(8).eof(EOFKind::EndAddOne).build();

    let mut input_reader = BitReader::<_, MSB>::new(data);
    let mut decoder = ArithmeticDecoder::new(48);
    let mut decompressed_data = vec![];

    while !decoder.finished() {
        let sym = decoder.decode(&model, &mut input_reader).unwrap();
        model.update_symbol(sym);
        decompressed_data.push(sym as u8);
    }
}

pub fn bench_encode(c: &mut Criterion) {
    let scale = 300;
    let sherlock_bytes = sherlock::SHERLOCK.bytes().into_iter().collect::<Vec<u8>>();
    let sherlock_bytes = sherlock_bytes.repeat(scale);
    let compressed_bytes = encode_return(&sherlock_bytes);

    let byte = Byte::from_bytes(sherlock_bytes.len() as u128);
    let label_encode = byte.get_appropriate_unit(false).to_string();
    let byte = Byte::from_bytes(compressed_bytes.len() as u128);
    let label_decode = byte.get_appropriate_unit(false).to_string();

    c.bench_with_input(
        BenchmarkId::new("encode_single", label_encode),
        &sherlock_bytes,
        |b, data| {
            b.iter(|| encode(data));
        },
    );

    c.bench_with_input(
        BenchmarkId::new("decode_single", label_decode),
        &compressed_bytes,
        |b, data| {
            b.iter(|| decode(data));
        },
    );
}

criterion_group!(benches, bench_encode);
criterion_main!(benches);