pub const fn fnv1a(bytes: &[u8]) -> u64 {
let mut h: u64 = 0xcbf2_9ce4_8422_2325;
let mut i = 0usize;
while i < bytes.len() {
h ^= bytes[i] as u64;
h = h.wrapping_mul(0x0000_0100_0000_01b3);
i += 1;
}
h
}
pub fn fnv1a_str(s: &str) -> u64 {
fnv1a(s.as_bytes())
}
pub fn fnv1a_parts(parts: &[u64]) -> u64 {
let mut h: u64 = 0xcbf2_9ce4_8422_2325;
for &p in parts {
let mut shift = 0usize;
while shift < 8 {
h ^= (p >> (shift * 8)) & 0xff;
h = h.wrapping_mul(0x0000_0100_0000_01b3);
shift += 1;
}
}
h
}
pub fn fnv1a_combine(acc: u64, next: u64) -> u64 {
let mut h = acc ^ 0x9e37_79b9_7f4a_7c15;
let mut shift = 0usize;
while shift < 8 {
h ^= (next >> (shift * 8)) & 0xff;
h = h.wrapping_mul(0x0000_0100_0000_01b3);
shift += 1;
}
h
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn fnv1a_known_vector() {
assert_eq!(fnv1a(b""), 0xcbf2_9ce4_8422_2325);
assert_eq!(fnv1a(b"a"), 0xaf63_dc4c_8601_ec8c);
}
#[test]
fn parts_combine_is_stable() {
assert_eq!(fnv1a_parts(&[1, 2, 3]), fnv1a_parts(&[1, 2, 3]));
assert_ne!(fnv1a_parts(&[1, 2, 3]), fnv1a_parts(&[1, 2, 4]));
}
#[test]
fn str_matches_bytes() {
assert_eq!(fnv1a_str("hello"), fnv1a(b"hello"));
}
}