1use core::fmt::{Debug, Formatter};
2use core::hash::Hasher;
3
4#[derive(Clone)]
18pub struct Mx3Hasher {
19 seed: u64,
20 state: u64,
21 buf: [u8; 1024],
22 buf_filled: usize,
23}
24
25impl Mx3Hasher {
26 pub fn new(seed: u64) -> Self {
31 Self {
32 seed,
33 state: crate::v3::mix(seed),
34 buf: [0u8; 1024],
35 buf_filled: 0,
36 }
37 }
38}
39
40impl Hasher for Mx3Hasher {
41 fn write(&mut self, bytes: &[u8]) {
42 let mut remain = bytes;
43
44 while !remain.is_empty() {
45 let amount = bytes.len().min(self.buf.len() - self.buf_filled);
46 let (left, right) = bytes.split_at(amount);
47
48 self.buf[self.buf_filled..self.buf_filled + amount].copy_from_slice(left);
49 self.buf_filled += amount;
50
51 debug_assert!(self.buf_filled <= self.buf.len());
52
53 if self.buf_filled == self.buf.len() {
54 self.state ^= crate::v3::hash(&self.buf, self.seed);
55 self.buf_filled = 0;
56 }
57
58 remain = right;
59 }
60 }
61
62 fn finish(&self) -> u64 {
63 let mut output = self.state;
64
65 if self.buf_filled > 0 {
66 output ^= crate::v3::hash(&self.buf[0..self.buf_filled], self.seed);
67 }
68
69 output
70 }
71}
72
73impl Debug for Mx3Hasher {
74 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
75 write!(f, "Mx3Hasher {{...}}")
76 }
77}
78
79impl Default for Mx3Hasher {
80 fn default() -> Self {
81 Self::new(1)
82 }
83}
84
85#[cfg(test)]
86mod tests {
87 use super::*;
88
89 #[test]
90 fn test_mx3hasher() {
91 let input = b"abcdefghijklmnopqrstuvwxyz";
92 let mut hasher = Mx3Hasher::new(123456789);
93
94 for _ in 0..100 {
95 hasher.write(input);
96 }
97
98 assert_eq!(hasher.finish(), 8878623092709932526);
99 }
100
101 #[test]
102 fn test_mx3hasher_empty() {
103 let input = b"";
104 let mut hasher = Mx3Hasher::new(123456789);
105 hasher.write(input);
106 assert_eq!(hasher.finish(), 0x95bd1de6327dae0a);
107 }
108
109 #[test]
110 fn test_debug() {
111 let hasher = Mx3Hasher::default();
112 format_args!("{:?}", hasher);
113 }
114
115 #[test]
116 fn test_clone() {
117 let mut hasher = Mx3Hasher::default();
118 hasher.write(b"abc");
119
120 let hasher2 = hasher.clone();
121
122 assert_eq!(hasher.finish(), hasher2.finish());
123 }
124}