const OFFSET_BASIS: u64 = 0xcbf2_9ce4_8422_2325;
const PRIME: u64 = 0x0000_0100_0000_01b3;
#[derive(Clone, Debug)]
pub struct Hasher {
state: u64,
}
impl Default for Hasher {
fn default() -> Hasher {
Hasher::new()
}
}
impl Hasher {
pub fn new() -> Hasher {
Hasher {
state: OFFSET_BASIS,
}
}
pub fn bytes(&mut self, data: &[u8]) -> &mut Hasher {
for &byte in data {
self.state ^= u64::from(byte);
self.state = self.state.wrapping_mul(PRIME);
}
self
}
pub fn u8(&mut self, value: u8) -> &mut Hasher {
self.bytes(&[value])
}
pub fn u16(&mut self, value: u16) -> &mut Hasher {
self.bytes(&value.to_le_bytes())
}
pub fn u32(&mut self, value: u32) -> &mut Hasher {
self.bytes(&value.to_le_bytes())
}
pub fn u64(&mut self, value: u64) -> &mut Hasher {
self.bytes(&value.to_le_bytes())
}
pub fn i32(&mut self, value: i32) -> &mut Hasher {
self.bytes(&value.to_le_bytes())
}
pub fn bool(&mut self, value: bool) -> &mut Hasher {
self.u8(u8::from(value))
}
pub fn f32(&mut self, value: f32) -> &mut Hasher {
let bits = if value.is_nan() {
0x7fc0_0000
} else {
value.to_bits()
};
self.u32(bits)
}
pub fn str(&mut self, text: &str) -> &mut Hasher {
self.u32(text.len() as u32).bytes(text.as_bytes())
}
pub fn finish(&self) -> u64 {
self.state
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn default_is_new() {
assert_eq!(Hasher::default().finish(), Hasher::new().finish());
}
#[test]
fn empty_input_is_the_offset_basis() {
assert_eq!(Hasher::new().finish(), 0xcbf2_9ce4_8422_2325);
}
#[test]
fn u32_feeds_its_four_little_endian_bytes() {
let value = 0x0403_0201u32;
assert_eq!(
Hasher::new().u32(value).finish(),
Hasher::new().bytes(&[1, 2, 3, 4]).finish()
);
}
#[test]
fn every_nan_hashes_the_same_and_zero_and_negative_zero_differ() {
let nan_a = f32::from_bits(0x7fc0_0000);
let nan_b = f32::from_bits(0x7fc0_0001);
assert_eq!(
Hasher::new().f32(nan_a).finish(),
Hasher::new().f32(nan_b).finish()
);
assert_ne!(
Hasher::new().f32(0.0).finish(),
Hasher::new().f32(-0.0).finish()
);
}
#[test]
fn nan_is_hashed_as_the_canonical_bits_7fc00000() {
assert_eq!(
Hasher::new().f32(f32::from_bits(0x7fc0_0001)).finish(),
Hasher::new().u32(0x7fc0_0000).finish()
);
}
#[test]
fn strings_are_length_prefixed_so_splits_do_not_collide() {
let split_early = Hasher::new().str("ab").str("c").finish();
let split_late = Hasher::new().str("a").str("bc").finish();
assert_ne!(split_early, split_late);
assert_eq!(
Hasher::new().str("ab").finish(),
Hasher::new().str("ab").finish()
);
}
#[test]
fn small_integers_and_bools_feed_their_little_endian_bytes() {
assert_eq!(
Hasher::new().u8(7).finish(),
Hasher::new().bytes(&[7]).finish()
);
assert_eq!(
Hasher::new().u16(0x0102).finish(),
Hasher::new().bytes(&[2, 1]).finish()
);
assert_eq!(
Hasher::new().i32(-1).finish(),
Hasher::new().bytes(&[0xFF; 4]).finish()
);
assert_eq!(
Hasher::new().u64(1).finish(),
Hasher::new().bytes(&[1, 0, 0, 0, 0, 0, 0, 0]).finish()
);
assert_eq!(
Hasher::new().bool(true).finish(),
Hasher::new().bytes(&[1]).finish()
);
assert_eq!(
Hasher::new().bool(false).finish(),
Hasher::new().bytes(&[0]).finish()
);
}
#[test]
fn matches_the_published_fnv1a_vectors() {
assert_eq!(Hasher::new().bytes(b"a").finish(), 0xaf63_dc4c_8601_ec8c);
assert_eq!(
Hasher::new().bytes(b"foobar").finish(),
0x8594_4171_f739_67e8
);
}
#[test]
fn order_matters() {
assert_ne!(
Hasher::new().u8(1).u8(2).finish(),
Hasher::new().u8(2).u8(1).finish()
);
}
#[test]
fn finish_does_not_consume_or_reset() {
let mut h = Hasher::new();
h.u32(9);
let first = h.finish();
assert_eq!(h.finish(), first);
h.u8(0);
assert_ne!(h.finish(), first);
}
}