pub(crate) const FNV_OFFSET: u64 = 14_695_981_039_346_656_037;
pub(crate) const FNV_PRIME: u64 = 1_099_511_628_211;
#[inline]
pub(crate) fn fnv1a_64(bytes: &[u8]) -> u64 {
let mut h = FNV_OFFSET;
for &b in bytes {
h ^= b as u64;
h = h.wrapping_mul(FNV_PRIME);
}
h
}
#[inline]
pub(crate) fn fnv1a_64_extend(mut h: u64, bytes: &[u8]) -> u64 {
for &b in bytes {
h ^= b as u64;
h = h.wrapping_mul(FNV_PRIME);
}
h
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn fnv1a_64_empty_is_offset_basis() {
assert_eq!(fnv1a_64(b""), FNV_OFFSET);
}
#[test]
fn fnv1a_64_known_vectors() {
assert_eq!(fnv1a_64(b"foobar"), 0x85944171f73967e8);
}
#[test]
fn fnv1a_64_different_inputs_differ() {
assert_ne!(fnv1a_64(b"hello"), fnv1a_64(b"world"));
}
#[test]
fn fnv1a_64_extend_matches_single_call() {
let combined = fnv1a_64(b"foobar");
let mut h = FNV_OFFSET;
h = fnv1a_64_extend(h, b"foo");
h = fnv1a_64_extend(h, b"bar");
assert_eq!(h, combined);
}
#[test]
fn fnv1a_64_extend_from_mid_hash() {
let a = fnv1a_64(b"prefix");
let extended = fnv1a_64_extend(a, b"suffix");
let full = fnv1a_64(b"prefixsuffix");
assert_eq!(extended, full);
}
}