zstd-complete 0.3.0

A pure Rust Zstandard compressor and decompressor with bounded streaming I/O
Documentation
#[derive(Clone, Copy)]
struct SmallLengthCode {
    add_bits: u32,
    code: u8,
    num_bits: u8,
}

const _: () = assert!(core::mem::size_of::<SmallLengthCode>() == 8);

const LITERAL_LENGTH_SMALL_CODES: [SmallLengthCode; 64] = small_literal_length_codes();
const MATCH_LENGTH_SMALL_CODES: [SmallLengthCode; 128] = small_match_length_codes();

#[inline(always)]
pub(crate) fn literal_length_code(len: u32) -> u8 {
    encode_literal_length(len).0
}

#[inline(always)]
pub(crate) fn match_length_code(len: u32) -> u8 {
    encode_match_len(len).0
}

#[inline(always)]
pub(crate) fn offset_code(offset_value: u32) -> u8 {
    encode_offset(offset_value).0
}

#[inline(always)]
pub(super) fn encode_literal_length(len: u32) -> (u8, u32, usize) {
    if len < LITERAL_LENGTH_SMALL_CODES.len() as u32 {
        let entry = LITERAL_LENGTH_SMALL_CODES[len as usize];
        return (entry.code, entry.add_bits, usize::from(entry.num_bits));
    }

    match len {
        0..=63 => unreachable!(),
        64..=127 => (25, len - 64, 6),
        128..=255 => (26, len - 128, 7),
        256..=511 => (27, len - 256, 8),
        512..=1023 => (28, len - 512, 9),
        1024..=2047 => (29, len - 1024, 10),
        2048..=4095 => (30, len - 2048, 11),
        4096..=8191 => (31, len - 4096, 12),
        8192..=16383 => (32, len - 8192, 13),
        16384..=32767 => (33, len - 16384, 14),
        32768..=65535 => (34, len - 32768, 15),
        65536..=131071 => (35, len - 65536, 16),
        131072.. => unreachable!(),
    }
}

#[inline(always)]
pub(super) fn encode_match_len(len: u32) -> (u8, u32, usize) {
    if (3..=130).contains(&len) {
        let entry = MATCH_LENGTH_SMALL_CODES[(len - 3) as usize];
        return (entry.code, entry.add_bits, usize::from(entry.num_bits));
    }

    match len {
        0..=2 => unreachable!(),
        3..=130 => unreachable!(),
        131..=258 => (43, len - 131, 7),
        259..=514 => (44, len - 259, 8),
        515..=1026 => (45, len - 515, 9),
        1027..=2050 => (46, len - 1027, 10),
        2051..=4098 => (47, len - 2051, 11),
        4099..=8194 => (48, len - 4099, 12),
        8195..=16386 => (49, len - 8195, 13),
        16387..=32770 => (50, len - 16387, 14),
        32771..=65538 => (51, len - 32771, 15),
        65539..=131074 => (52, len - 65539, 16),
        131075.. => unreachable!(),
    }
}

const fn small_literal_length_codes() -> [SmallLengthCode; 64] {
    let mut codes = [SmallLengthCode {
        add_bits: 0,
        code: 0,
        num_bits: 0,
    }; 64];
    let mut len = 0usize;
    while len < codes.len() {
        let (code, add_bits, num_bits) = match len {
            0..=15 => (len as u8, 0, 0),
            16..=17 => (16, len as u32 - 16, 1),
            18..=19 => (17, len as u32 - 18, 1),
            20..=21 => (18, len as u32 - 20, 1),
            22..=23 => (19, len as u32 - 22, 1),
            24..=27 => (20, len as u32 - 24, 2),
            28..=31 => (21, len as u32 - 28, 2),
            32..=39 => (22, len as u32 - 32, 3),
            40..=47 => (23, len as u32 - 40, 3),
            48..=63 => (24, len as u32 - 48, 4),
            _ => unreachable!(),
        };
        codes[len] = SmallLengthCode {
            add_bits,
            code,
            num_bits: num_bits as u8,
        };
        len += 1;
    }
    codes
}

const fn small_match_length_codes() -> [SmallLengthCode; 128] {
    let mut codes = [SmallLengthCode {
        add_bits: 0,
        code: 0,
        num_bits: 0,
    }; 128];
    let mut idx = 0usize;
    while idx < codes.len() {
        let len = idx + 3;
        let (code, add_bits, num_bits) = match len {
            3..=34 => (len as u8 - 3, 0, 0),
            35..=36 => (32, len as u32 - 35, 1),
            37..=38 => (33, len as u32 - 37, 1),
            39..=40 => (34, len as u32 - 39, 1),
            41..=42 => (35, len as u32 - 41, 1),
            43..=46 => (36, len as u32 - 43, 2),
            47..=50 => (37, len as u32 - 47, 2),
            51..=58 => (38, len as u32 - 51, 3),
            59..=66 => (39, len as u32 - 59, 3),
            67..=82 => (40, len as u32 - 67, 4),
            83..=98 => (41, len as u32 - 83, 4),
            99..=130 => (42, len as u32 - 99, 5),
            _ => unreachable!(),
        };
        codes[idx] = SmallLengthCode {
            add_bits,
            code,
            num_bits: num_bits as u8,
        };
        idx += 1;
    }
    codes
}

#[inline(always)]
pub(super) fn encode_offset(len: u32) -> (u8, u32, usize) {
    let log = len.ilog2();
    let lower = len & ((1 << log) - 1);
    (log as u8, lower, log as usize)
}