1#[derive(Clone, Copy)]
4pub struct Fnv1a64(u64);
5
6impl Fnv1a64 {
7 const PRIME: u64 = 0x0000_0100_0000_01b3;
8
9 #[must_use]
10 pub const fn new() -> Self {
11 Self(0xcbf2_9ce4_8422_2325)
12 }
13
14 #[must_use]
15 pub const fn write(self, bytes: &[u8]) -> Self {
16 let mut hash = self.0;
17 let mut index = 0;
18 while index < bytes.len() {
19 hash ^= bytes[index] as u64;
20 hash = hash.wrapping_mul(Self::PRIME);
21 index += 1;
22 }
23 Self(hash)
24 }
25
26 #[must_use]
27 pub const fn finish(self) -> u64 {
28 self.0
29 }
30}
31
32impl Default for Fnv1a64 {
33 fn default() -> Self {
34 Self::new()
35 }
36}
37
38#[cfg(test)]
39mod tests {
40 use super::Fnv1a64;
41
42 fn hash(bytes: &[u8]) -> u64 {
43 Fnv1a64::new().write(bytes).finish()
44 }
45
46 #[test]
47 fn hashes_like_the_reference_fnv1a() {
48 assert_eq!(hash(b""), 0xcbf2_9ce4_8422_2325);
49 assert_eq!(hash(b"a"), 0xaf63_dc4c_8601_ec8c);
50 assert_eq!(hash(b"foobar"), 0x8594_4171_f739_67e8);
51 }
52
53 #[test]
54 fn writing_in_pieces_hashes_like_writing_at_once() {
55 let pieces = Fnv1a64::new().write(b"foo").write(b"").write(b"bar");
56 assert_eq!(pieces.finish(), hash(b"foobar"));
57 }
58}