devela/data/codec/hash/
fx.rs
1use crate::{ConstDefault, Hash, Hasher, HasherBuildDefault};
4
5pub type HasherBuildFx = HasherBuildDefault<HasherFx<usize>>;
7
8#[doc = crate::doc_!(vendor: "fxhash")]
21#[must_use]
22#[derive(Clone, Copy, Debug, PartialEq, Eq)]
23pub struct HasherFx<T> {
24 state: T,
25}
26
27const ROTATE: u32 = 5;
28const SEED32: u32 = 0x9e_37_79_b9;
29const SEED64: u64 = 0x51_7c_c1_b7_27_22_0a_95;
30#[cfg(target_pointer_width = "32")]
31const SEED: usize = SEED32 as usize;
32#[cfg(target_pointer_width = "64")]
33const SEED: usize = SEED64 as usize;
34
35macro_rules! impl_fx {
36 () => { impl_fx![u32:SEED32, u64:SEED64, usize:SEED]; };
37
38 ($($t:ty:$seed:ident),+) => { $( impl_fx![@$t:$seed]; )+ };
39 (@$t:ty:$seed:ident) => {
40 impl ConstDefault for HasherFx<$t> { const DEFAULT: Self = Self { state: 0 }; }
41 impl Default for HasherFx<$t> { fn default() -> Self { Self::DEFAULT } }
42
43 impl HasherFx<$t> {
44 pub const fn new() -> Self { Self::DEFAULT }
48
49 pub const fn with_seed(seed: $t) -> Self { Self { state: seed } }
51
52 pub fn hash<T: Hash + ?Sized>(v: &T) -> $t {
54 let mut state = Self::new();
55 v.hash(&mut state);
56 state.state
57 }
58
59 pub const fn hash_bytes(v: &[u8]) -> $t {
63 Self::hash_bytes_with_seed(0, v)
64 }
65
66 pub const fn hash_bytes_with_seed(seed: $t, v: &[u8]) -> $t {
70 Self::write(seed, v)
71 }
72
73 const fn hash_word(mut hash: $t, word: $t) -> $t {
74 hash = hash.rotate_left(ROTATE);
75 hash ^= word;
76 hash = hash.wrapping_mul($seed);
77 hash
78 }
79 }
80 };
81}
82impl_fx!();
83
84impl HasherFx<u32> {
87 const fn write(mut hash: u32, bytes: &[u8]) -> u32 {
88 let mut cursor = 0;
89 while bytes.len() - cursor >= 4 {
90 let word = u32::from_ne_bytes([
91 bytes[cursor],
92 bytes[cursor + 1],
93 bytes[cursor + 2],
94 bytes[cursor + 3],
95 ]);
96 hash = Self::hash_word(hash, word);
97 cursor += 4;
98 }
99 if bytes.len() - cursor >= 2 {
100 let word = u16::from_ne_bytes([bytes[cursor], bytes[cursor + 1]]);
101 hash = Self::hash_word(hash, word as u32);
102 cursor += 2;
103 }
104 if bytes.len() - cursor >= 1 {
105 hash = Self::hash_word(hash, bytes[cursor] as u32);
106 }
107 hash
108 }
109}
110
111impl HasherFx<u64> {
112 const fn write(mut hash: u64, bytes: &[u8]) -> u64 {
113 let mut cursor = 0;
114 while bytes.len() - cursor >= 8 {
115 let word = u64::from_ne_bytes([
116 bytes[cursor],
117 bytes[cursor + 1],
118 bytes[cursor + 2],
119 bytes[cursor + 3],
120 bytes[cursor + 4],
121 bytes[cursor + 5],
122 bytes[cursor + 6],
123 bytes[cursor + 7],
124 ]);
125 hash = Self::hash_word(hash, word);
126 cursor += 8;
127 }
128 while bytes.len() - cursor >= 4 {
129 let word = u32::from_ne_bytes([
130 bytes[cursor],
131 bytes[cursor + 1],
132 bytes[cursor + 2],
133 bytes[cursor + 3],
134 ]);
135 hash = Self::hash_word(hash, word as u64);
136 cursor += 4;
137 }
138 if bytes.len() - cursor >= 2 {
139 let word = u16::from_ne_bytes([bytes[cursor], bytes[cursor + 1]]);
140 hash = Self::hash_word(hash, word as u64);
141 cursor += 2;
142 }
143 if bytes.len() - cursor >= 1 {
144 hash = Self::hash_word(hash, bytes[cursor] as u64);
145 }
146 hash
147 }
148}
149
150impl HasherFx<usize> {
151 const fn write(hash: usize, bytes: &[u8]) -> usize {
152 #[cfg(target_pointer_width = "32")]
153 return HasherFx::<u32>::write(hash as u32, bytes) as usize;
154 #[cfg(target_pointer_width = "64")]
155 return HasherFx::<u64>::write(hash as u64, bytes) as usize;
156 }
157}
158
159impl Hasher for HasherFx<u32> {
162 fn write(&mut self, bytes: &[u8]) {
163 self.state = Self::write(self.state, bytes);
164 }
165 fn write_u8(&mut self, i: u8) {
166 self.state = Self::hash_word(self.state, u32::from(i));
167 }
168 fn write_u16(&mut self, i: u16) {
169 self.state = Self::hash_word(self.state, u32::from(i));
170 }
171 fn write_u32(&mut self, i: u32) {
172 self.state = Self::hash_word(self.state, i);
173 }
174 fn write_u64(&mut self, i: u64) {
175 self.state = Self::hash_word(self.state, i as u32);
176 self.state = Self::hash_word(self.state, (i >> 32) as u32);
177 }
178 fn write_usize(&mut self, i: usize) {
179 #[cfg(target_pointer_width = "32")]
180 self.write_u32(i as u32);
181 #[cfg(target_pointer_width = "64")]
182 self.write_u64(i as u64);
183 }
184 fn finish(&self) -> u64 {
185 self.state as u64
186 }
187}
188impl Hasher for HasherFx<u64> {
189 fn write(&mut self, bytes: &[u8]) {
190 self.state = Self::write(self.state, bytes);
191 }
192 fn write_u8(&mut self, i: u8) {
193 self.state = Self::hash_word(self.state, u64::from(i));
194 }
195 fn write_u16(&mut self, i: u16) {
196 self.state = Self::hash_word(self.state, u64::from(i));
197 }
198 fn write_u32(&mut self, i: u32) {
199 self.state = Self::hash_word(self.state, u64::from(i));
200 }
201 fn write_u64(&mut self, i: u64) {
202 self.state = Self::hash_word(self.state, i);
203 }
204 fn write_usize(&mut self, i: usize) {
205 self.state = Self::hash_word(self.state, i as u64);
206 }
207 fn finish(&self) -> u64 {
208 self.state
209 }
210}
211impl Hasher for HasherFx<usize> {
212 fn write(&mut self, bytes: &[u8]) {
213 self.state = Self::write(self.state, bytes);
214 }
215 fn write_u8(&mut self, i: u8) {
216 self.state = Self::hash_word(self.state, i as usize);
217 }
218 fn write_u16(&mut self, i: u16) {
219 self.state = Self::hash_word(self.state, i as usize);
220 }
221 fn write_u32(&mut self, i: u32) {
222 self.state = Self::hash_word(self.state, i as usize);
223 }
224 #[cfg(target_pointer_width = "32")]
225 fn write_u64(&mut self, i: u64) {
226 self.state = Self::hash_word(self.state, i as usize);
227 self.state = Self::hash_word(self.state, (i >> 32) as usize);
228 }
229 #[cfg(target_pointer_width = "64")]
230 fn write_u64(&mut self, i: u64) {
231 self.state = Self::hash_word(self.state, i as usize);
232 }
233 fn write_usize(&mut self, i: usize) {
234 self.state = HasherFx::<usize>::hash_word(self.state, i);
235 }
236 fn finish(&self) -> u64 {
237 self.state as u64
238 }
239}