cqdb 0.6.0

Rust implementation of Constant Quark Database (CQDB)
Documentation
use ::jhash::{JHASH_INITVAL, jhash_final, jhash_mix};

#[must_use]
pub fn jhash(mut key: &[u8], mut length: u32, initval: u32) -> u32 {
    let mut a = JHASH_INITVAL.wrapping_add(length).wrapping_add(initval);
    let mut b = a;
    let mut c = a;

    while length > 12 {
        use std::convert::TryInto;
        a = a.wrapping_add(u32::from_ne_bytes(key[..4].try_into().unwrap()));
        b = b.wrapping_add(u32::from_ne_bytes(key[4..8].try_into().unwrap()));
        c = c.wrapping_add(u32::from_ne_bytes(key[8..12].try_into().unwrap()));
        jhash_mix(&mut a, &mut b, &mut c);
        key = &key[12..];
        length -= 12;
    }

    if length == 0 {
        return c;
    }

    c = c.wrapping_add((*key.get(11).unwrap_or(&0) as u32) << 24);
    c = c.wrapping_add((*key.get(10).unwrap_or(&0) as u32) << 16);
    c = c.wrapping_add((*key.get(9).unwrap_or(&0) as u32) << 8);
    c = c.wrapping_add(*key.get(8).unwrap_or(&0) as u32);

    b = b.wrapping_add((*key.get(7).unwrap_or(&0) as u32) << 24);
    b = b.wrapping_add((*key.get(6).unwrap_or(&0) as u32) << 16);
    b = b.wrapping_add((*key.get(5).unwrap_or(&0) as u32) << 8);
    b = b.wrapping_add(*key.get(4).unwrap_or(&0) as u32);

    a = a.wrapping_add((*key.get(3).unwrap_or(&0) as u32) << 24);
    a = a.wrapping_add((*key.get(2).unwrap_or(&0) as u32) << 16);
    a = a.wrapping_add((*key.get(1).unwrap_or(&0) as u32) << 8);
    a = a.wrapping_add(*key.first().unwrap_or(&0) as u32);

    jhash_final(a, b, c)
}

#[cfg(test)]
mod tests {
    use super::jhash;

    #[test]
    fn test_jhash_multiple_of_12() {
        let s = b"0123456789ab";
        assert_eq!(s.len(), 12);
        let h = jhash(s, s.len() as u32 + 1, 0);
        assert_eq!(h, 2677502765);
    }

    #[test]
    fn test_jhash_multiple_of_12_again() {
        let s = b"0123456789ab0123456789ab";
        assert_eq!(s.len(), 24);
        let h = jhash(s, s.len() as u32 + 1, 0);
        assert_eq!(h, 1248740946);
    }
}