paku 0.0.2

Collection of decompressors in pure safe Rust.
Documentation
const PRIME32_1: u32 = 0x9E3779B1;
const PRIME32_2: u32 = 0x85EBCA77;
const PRIME32_3: u32 = 0xC2B2AE3D;
const PRIME32_4: u32 = 0x27D4EB2F;
const PRIME32_5: u32 = 0x165667B1;

pub struct XXHash32 {
    v1: u32,
    v2: u32,
    v3: u32,
    v4: u32,
    buf: Box<[u8]>,
    buf_used: usize,
    did_at_least_one_full_round: bool,
    total_len_mod_32_bit: u32,
}

impl XXHash32 {
    pub fn new(seed: u32) -> XXHash32 {
        XXHash32 {
            v1: seed.wrapping_add(PRIME32_1).wrapping_add(PRIME32_2),
            v2: seed.wrapping_add(PRIME32_2),
            v3: seed,
            v4: seed.wrapping_sub(PRIME32_1),
            buf: vec![0; 16].into_boxed_slice(),
            buf_used: 0,
            did_at_least_one_full_round: false,
            total_len_mod_32_bit: 0,
        }
    }

    pub fn update(&mut self, input: &[u8]) {
        let input_len = input.len();

        self.total_len_mod_32_bit = self.total_len_mod_32_bit.wrapping_add(input_len as u32);

        if input_len >= 16 || self.total_len_mod_32_bit >= 16 {
            self.did_at_least_one_full_round = true;
        }

        let mut remaining = self.buf_used + input_len;

        if remaining < 16 {
            self.buf[self.buf_used..remaining].copy_from_slice(input);
            self.buf_used += input_len;
            return;
        }

        let mut input_offset = 0;

        if self.buf_used != 0 {
            input_offset += 16 - self.buf_used;
            self.buf[self.buf_used..].copy_from_slice(&input[..input_offset]);

            self.v1 = Self::round(self.v1, Self::read32le(&self.buf, 0));
            self.v2 = Self::round(self.v2, Self::read32le(&self.buf, 4));
            self.v3 = Self::round(self.v3, Self::read32le(&self.buf, 8));
            self.v4 = Self::round(self.v4, Self::read32le(&self.buf, 12));

            remaining -= 16;
            self.buf_used = 0;
        }

        while remaining >= 16 {
            self.v1 = Self::round(self.v1, Self::read32le(input, input_offset));
            self.v2 = Self::round(self.v2, Self::read32le(input, input_offset + 4));
            self.v3 = Self::round(self.v3, Self::read32le(input, input_offset + 8));
            self.v4 = Self::round(self.v4, Self::read32le(input, input_offset + 12));

            input_offset += 16;
            remaining -= 16;
        }

        if remaining != 0 {
            self.buf[..remaining].copy_from_slice(&input[input_offset..]);
            self.buf_used = remaining;
        }
    }

    pub fn digest(&self) -> u32 {
        let mut hash = if self.did_at_least_one_full_round {
            let v1 = self.v1.rotate_left(1);
            let v2 = self.v2.rotate_left(7);
            let v3 = self.v3.rotate_left(12);
            let v4 = self.v4.rotate_left(18);
            v1.wrapping_add(v2).wrapping_add(v3).wrapping_add(v4)
        } else {
            self.v3.wrapping_add(PRIME32_5)
        };

        hash += self.total_len_mod_32_bit;

        let mut offset = 0;
        let mut remaining = self.buf_used;

        while remaining >= 4 {
            hash = hash.wrapping_add(Self::read32le(&self.buf, offset).wrapping_mul(PRIME32_3));
            hash = hash.rotate_left(17);
            hash = hash.wrapping_mul(PRIME32_4);

            offset += 4;
            remaining -= 4;
        }

        while remaining != 0 {
            hash = hash.wrapping_add((self.buf[offset] as u32).wrapping_mul(PRIME32_5));
            hash = hash.rotate_left(11);
            hash = hash.wrapping_mul(PRIME32_1);

            offset += 1;
            remaining -= 1;
        }

        Self::avalanche(hash)
    }

    fn read32le(input: &[u8], offset: usize) -> u32 {
        (input[offset] as u32)
            | ((input[offset + 1] as u32) << 8)
            | ((input[offset + 2] as u32) << 16)
            | ((input[offset + 3] as u32) << 24)
    }

    fn round(v: u32, input: u32) -> u32 {
        let v = v.wrapping_add(input.wrapping_mul(PRIME32_2));
        let v = v.rotate_left(13);
        v.wrapping_mul(PRIME32_1)
    }

    fn avalanche(hash: u32) -> u32 {
        let hash = hash ^ (hash >> 15);
        let hash = hash.wrapping_mul(PRIME32_2);
        let hash = hash ^ (hash >> 13);
        let hash = hash.wrapping_mul(PRIME32_3);
        hash ^ (hash >> 16)
    }
}