1use crate::{
12 schema::{DataModelType, NamedType, NamedValue, NamedVariant},
13 Schema,
14};
15
16pub struct Fnv1a64Hasher {
18 state: u64,
19}
20
21impl Fnv1a64Hasher {
22 const BASIS: u64 = 0xcbf2_9ce4_8422_2325;
24 const PRIME: u64 = 0x0000_0100_0000_01b3;
25
26 pub fn new() -> Self {
28 Self { state: Self::BASIS }
29 }
30
31 pub fn update(&mut self, data: &[u8]) {
33 for b in data {
34 let ext = u64::from(*b);
35 self.state ^= ext;
36 self.state = self.state.wrapping_mul(Self::PRIME);
37 }
38 }
39
40 pub fn digest(self) -> u64 {
42 self.state
43 }
44
45 pub fn digest_bytes(self) -> [u8; 8] {
47 self.digest().to_le_bytes()
48 }
49}
50
51impl Default for Fnv1a64Hasher {
52 fn default() -> Self {
53 Self::new()
54 }
55}
56
57pub mod fnv1a64 {
58 use crate::schema::DataModelVariant;
60
61 use super::*;
62
63 pub const fn hash_ty_path<T: Schema + ?Sized>(path: &str) -> [u8; 8] {
65 let schema = T::SCHEMA;
66 let state = hash_update_str(Fnv1a64Hasher::BASIS, path);
67 hash_named_type(state, schema).to_le_bytes()
68 }
69
70 pub(crate) const fn hash_update(mut state: u64, bytes: &[u8]) -> u64 {
71 let mut idx = 0;
72 while idx < bytes.len() {
73 let ext = bytes[idx] as u64;
74 state ^= ext;
75 state = state.wrapping_mul(Fnv1a64Hasher::PRIME);
76 idx += 1;
77 }
78 state
79 }
80
81 pub(crate) const fn hash_update_str(state: u64, s: &str) -> u64 {
82 hash_update(state, s.as_bytes())
83 }
84
85 const fn hash_sdm_type(state: u64, sdmty: &'static DataModelType) -> u64 {
86 match sdmty {
116 DataModelType::Bool => hash_update(state, &[0x11]),
117 DataModelType::I8 => hash_update(state, &[0xC5]),
118 DataModelType::U8 => hash_update(state, &[0x3D]),
119 DataModelType::I16 => hash_update(state, &[0x1D]),
120 DataModelType::I32 => hash_update(state, &[0x0D]),
121 DataModelType::I64 => hash_update(state, &[0x0B]),
122 DataModelType::I128 => hash_update(state, &[0x02]),
123 DataModelType::U16 => hash_update(state, &[0x83]),
124 DataModelType::U32 => hash_update(state, &[0xD3]),
125 DataModelType::U64 => hash_update(state, &[0x13]),
126 DataModelType::U128 => hash_update(state, &[0x8B]),
127 DataModelType::Usize => hash_update(state, &[0x6B]),
128 DataModelType::Isize => hash_update(state, &[0xAD]),
129 DataModelType::F32 => hash_update(state, &[0xEF]),
130 DataModelType::F64 => hash_update(state, &[0x71]),
131 DataModelType::Char => hash_update(state, &[0xC1]),
132 DataModelType::String => hash_update(state, &[0x25]),
133 DataModelType::ByteArray => hash_update(state, &[0x65]),
134 DataModelType::Option(nt) => {
135 let state = hash_update(state, &[0x6D]);
136 hash_named_type(state, nt)
137 }
138 DataModelType::Unit => hash_update(state, &[0x47]),
139 DataModelType::UnitStruct => hash_update(state, &[0xBF]),
140 DataModelType::NewtypeStruct(nt) => {
141 let state = hash_update(state, &[0x9D]);
142 hash_named_type(state, nt)
143 }
144 DataModelType::Seq(nt) => {
145 let state = hash_update(state, &[0x03]);
146 hash_named_type(state, nt)
147 }
148 DataModelType::Tuple(nts) => {
149 let mut state = hash_update(state, &[0xA7]);
150 let mut idx = 0;
151 while idx < nts.len() {
152 state = hash_named_type(state, nts[idx]);
153 idx += 1;
154 }
155 state
156 }
157 DataModelType::TupleStruct(nts) => {
158 let mut state = hash_update(state, &[0x05]);
159 let mut idx = 0;
160 while idx < nts.len() {
161 state = hash_named_type(state, nts[idx]);
162 idx += 1;
163 }
164 state
165 }
166 DataModelType::Map { key, val } => {
167 let state = hash_update(state, &[0x4F]);
168 let state = hash_named_type(state, key);
169 hash_named_type(state, val)
170 }
171 DataModelType::Struct(nvs) => {
172 let mut state = hash_update(state, &[0x7F]);
173 let mut idx = 0;
174 while idx < nvs.len() {
175 state = hash_named_value(state, nvs[idx]);
176 idx += 1;
177 }
178 state
179 }
180 DataModelType::Enum(nvs) => {
181 let mut state = hash_update(state, &[0xE9]);
182 let mut idx = 0;
183 while idx < nvs.len() {
184 state = hash_named_variant(state, nvs[idx]);
185 idx += 1;
186 }
187 state
188 }
189 DataModelType::Schema => hash_update(state, &[0xB3]),
190 }
191 }
192
193 const fn hash_named_type(state: u64, nt: &NamedType) -> u64 {
194 hash_sdm_type(state, nt.ty)
201 }
202
203 const fn hash_named_variant(state: u64, nt: &NamedVariant) -> u64 {
204 let state = hash_update(state, nt.name.as_bytes());
205 match nt.ty {
206 DataModelVariant::UnitVariant => hash_update(state, &[0xB5]),
207 DataModelVariant::NewtypeVariant(nt) => {
208 let state = hash_update(state, &[0xDF]);
209 hash_named_type(state, nt)
210 }
211 DataModelVariant::TupleVariant(nts) => {
212 let mut state = hash_update(state, &[0xC7]);
213 let mut idx = 0;
214 while idx < nts.len() {
215 state = hash_named_type(state, nts[idx]);
216 idx += 1;
217 }
218 state
219 }
220 DataModelVariant::StructVariant(nvs) => {
221 let mut state = hash_update(state, &[0x67]);
222 let mut idx = 0;
223 while idx < nvs.len() {
224 state = hash_named_value(state, nvs[idx]);
225 idx += 1;
226 }
227 state
228 }
229 }
230 }
231
232 const fn hash_named_value(state: u64, nt: &NamedValue) -> u64 {
233 let state = hash_update(state, nt.name.as_bytes());
234 hash_named_type(state, nt.ty)
235 }
236}
237
238#[cfg(feature = "use-std")]
239pub mod fnv1a64_owned {
240 use crate::schema::owned::{
243 OwnedDataModelType, OwnedDataModelVariant, OwnedNamedType, OwnedNamedValue,
244 OwnedNamedVariant,
245 };
246
247 use super::fnv1a64::*;
248 use super::*;
249
250 pub fn hash_ty_path_owned(path: &str, nt: &OwnedNamedType) -> [u8; 8] {
252 let state = hash_update_str(Fnv1a64Hasher::BASIS, path);
253 hash_named_type_owned(state, nt).to_le_bytes()
254 }
255
256 fn hash_sdm_type_owned(state: u64, sdmty: &OwnedDataModelType) -> u64 {
257 match sdmty {
287 OwnedDataModelType::Bool => hash_update(state, &[0x11]),
288 OwnedDataModelType::I8 => hash_update(state, &[0xC5]),
289 OwnedDataModelType::U8 => hash_update(state, &[0x3D]),
290 OwnedDataModelType::I16 => hash_update(state, &[0x1D]),
291 OwnedDataModelType::I32 => hash_update(state, &[0x0D]),
292 OwnedDataModelType::I64 => hash_update(state, &[0x0B]),
293 OwnedDataModelType::I128 => hash_update(state, &[0x02]),
294 OwnedDataModelType::U16 => hash_update(state, &[0x83]),
295 OwnedDataModelType::U32 => hash_update(state, &[0xD3]),
296 OwnedDataModelType::U64 => hash_update(state, &[0x13]),
297 OwnedDataModelType::U128 => hash_update(state, &[0x8B]),
298 OwnedDataModelType::Usize => hash_update(state, &[0x6B]),
299 OwnedDataModelType::Isize => hash_update(state, &[0xAD]),
300 OwnedDataModelType::F32 => hash_update(state, &[0xEF]),
301 OwnedDataModelType::F64 => hash_update(state, &[0x71]),
302 OwnedDataModelType::Char => hash_update(state, &[0xC1]),
303 OwnedDataModelType::String => hash_update(state, &[0x25]),
304 OwnedDataModelType::ByteArray => hash_update(state, &[0x65]),
305 OwnedDataModelType::Option(nt) => {
306 let state = hash_update(state, &[0x6D]);
307 hash_named_type_owned(state, nt)
308 }
309 OwnedDataModelType::Unit => hash_update(state, &[0x47]),
310 OwnedDataModelType::UnitStruct => hash_update(state, &[0xBF]),
311 OwnedDataModelType::NewtypeStruct(nt) => {
312 let state = hash_update(state, &[0x9D]);
313 hash_named_type_owned(state, nt)
314 }
315 OwnedDataModelType::Seq(nt) => {
316 let state = hash_update(state, &[0x03]);
317 hash_named_type_owned(state, nt)
318 }
319 OwnedDataModelType::Tuple(nts) => {
320 let mut state = hash_update(state, &[0xA7]);
321 let mut idx = 0;
322 while idx < nts.len() {
323 state = hash_named_type_owned(state, &nts[idx]);
324 idx += 1;
325 }
326 state
327 }
328 OwnedDataModelType::TupleStruct(nts) => {
329 let mut state = hash_update(state, &[0x05]);
330 let mut idx = 0;
331 while idx < nts.len() {
332 state = hash_named_type_owned(state, &nts[idx]);
333 idx += 1;
334 }
335 state
336 }
337 OwnedDataModelType::Map { key, val } => {
338 let state = hash_update(state, &[0x4F]);
339 let state = hash_named_type_owned(state, key);
340 hash_named_type_owned(state, val)
341 }
342 OwnedDataModelType::Struct(nvs) => {
343 let mut state = hash_update(state, &[0x7F]);
344 let mut idx = 0;
345 while idx < nvs.len() {
346 state = hash_named_value_owned(state, &nvs[idx]);
347 idx += 1;
348 }
349 state
350 }
351 OwnedDataModelType::Enum(nvs) => {
352 let mut state = hash_update(state, &[0xE9]);
353 let mut idx = 0;
354 while idx < nvs.len() {
355 state = hash_named_variant_owned(state, &nvs[idx]);
356 idx += 1;
357 }
358 state
359 }
360 OwnedDataModelType::Schema => hash_update(state, &[0xB3]),
361 }
362 }
363
364 fn hash_named_type_owned(state: u64, nt: &OwnedNamedType) -> u64 {
365 hash_sdm_type_owned(state, &nt.ty)
372 }
373
374 fn hash_named_variant_owned(state: u64, nt: &OwnedNamedVariant) -> u64 {
375 let state = hash_update(state, nt.name.as_bytes());
376 match &nt.ty {
377 OwnedDataModelVariant::UnitVariant => hash_update(state, &[0xB5]),
378 OwnedDataModelVariant::NewtypeVariant(nt) => {
379 let state = hash_update(state, &[0xDF]);
380 hash_named_type_owned(state, nt)
381 }
382 OwnedDataModelVariant::TupleVariant(nts) => {
383 let mut state = hash_update(state, &[0xC7]);
384 let mut idx = 0;
385 while idx < nts.len() {
386 state = hash_named_type_owned(state, &nts[idx]);
387 idx += 1;
388 }
389 state
390 }
391 OwnedDataModelVariant::StructVariant(nvs) => {
392 let mut state = hash_update(state, &[0x67]);
393 let mut idx = 0;
394 while idx < nvs.len() {
395 state = hash_named_value_owned(state, &nvs[idx]);
396 idx += 1;
397 }
398 state
399 }
400 }
401 }
402
403 fn hash_named_value_owned(state: u64, nt: &OwnedNamedValue) -> u64 {
404 let state = hash_update(state, nt.name.as_bytes());
405 hash_named_type_owned(state, &nt.ty)
406 }
407}
408
409#[cfg(test)]
410mod test {
411 use super::fnv1a64::hash_ty_path;
412
413 #[test]
414 fn type_punning_good() {
415 let hash_1 = hash_ty_path::<Vec<u8>>("test_path");
416 let hash_2 = hash_ty_path::<&[u8]>("test_path");
417 let hash_3 = hash_ty_path::<Vec<u16>>("test_path");
418 let hash_4 = hash_ty_path::<&[u16]>("test_path");
419 let hash_5 = hash_ty_path::<Vec<u8>>("test_patt");
420 let hash_6 = hash_ty_path::<&[u8]>("test_patt");
421 assert_eq!(hash_1, hash_2);
422 assert_eq!(hash_3, hash_4);
423 assert_ne!(hash_1, hash_3);
424 assert_ne!(hash_2, hash_4);
425 assert_ne!(hash_1, hash_5);
426 assert_ne!(hash_2, hash_6);
427 }
428}