compactly 0.1.8

Compactly encode data types using adaptive arithmetic coding
Documentation
//! Focused benchmark for the enum-discriminant encode hot path (the
//! `AtMost<2>` walk); the encode-side twin of `just-decompress-enums`,
//! same data and distribution.
//!
//! Usage: `just-compress-enums [ans|range] [seventeen] [iterations]` (defaults:
//! `ans`, 3-variant, 2000).

#[derive(Debug, Clone, Copy, PartialEq, Eq, compactly::v2::Encode)]
enum ThreeOptions {
    A,
    B,
    C,
}

fn data() -> Vec<ThreeOptions> {
    // Simple LCG for reproducible pseudo-random skewed data, as in
    // `just-decompress`.
    let mut x = 0x123456789abcdef0u64;
    (0..100_000)
        .map(|_| {
            x = x
                .wrapping_mul(6364136223846793005)
                .wrapping_add(1442695040888963407);
            match (x >> 33) % 10 {
                0 | 1 => ThreeOptions::A,
                2 | 3 => ThreeOptions::B,
                _ => ThreeOptions::C,
            }
        })
        .collect()
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, compactly::v2::Encode)]
enum SeventeenOptions {
    A,
    B,
    C,
    D,
    E,
    F,
    G,
    H,
    I,
    J,
    K,
    L,
    M,
    N,
    O,
    P,
    Q,
}

fn data_seventeen() -> Vec<SeventeenOptions> {
    use SeventeenOptions::*;
    const VARIANTS: [SeventeenOptions; 17] = [A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q];
    let mut x = 0x123456789abcdef0u64;
    (0..100_000)
        .map(|_| {
            x = x
                .wrapping_mul(6364136223846793005)
                .wrapping_add(1442695040888963407);
            VARIANTS[((x >> 33) % 17) as usize]
        })
        .collect()
}

fn run<T: compactly::v2::Encode>(data: Vec<T>, coder: &str, iterations: usize) -> usize {
    let mut total = 0usize;
    match coder {
        "ans" => {
            for _ in 0..iterations {
                total += std::hint::black_box(compactly::v2::Ans::encode(&data)).len();
            }
        }
        "range" => {
            for _ in 0..iterations {
                total += std::hint::black_box(compactly::v2::encode(&data)).len();
            }
        }
        _ => unreachable!(),
    }
    total
}

fn main() {
    let coder = std::env::args()
        .find(|a| a == "ans" || a == "range")
        .unwrap_or("ans".to_string());
    let seventeen = std::env::args().any(|a| a == "seventeen");
    let iterations: usize = std::env::args()
        .filter_map(|a| a.parse().ok())
        .next()
        .unwrap_or(2000);
    let variants = if seventeen { 17 } else { 3 };
    println!("encoding 100000 {variants}-variant enums with {coder}");
    let total = if seventeen {
        run(data_seventeen(), &coder, iterations)
    } else {
        run(data(), &coder, iterations)
    };
    println!("total encoded {total}");
}