fingerprint_struct/
impls.rs

1#[allow(unused_imports)]
2use core::hash::Hash;
3
4use crate::Fingerprint;
5use digest::Update;
6
7macro_rules! impl_method {
8    ($type: ty, $member: ident ($($arg: expr),*)) => {
9        impl Fingerprint for $type {
10            #[inline(always)]
11            fn fingerprint<U: Update>(&self, hasher: &mut U) {
12                self.$member($($arg),*).fingerprint(hasher);
13            }
14        }
15    };
16}
17
18macro_rules! impl_inner {
19    ($type: ty) => {
20        impl<T: Fingerprint> Fingerprint for $type {
21            #[inline(always)]
22            fn fingerprint<U: Update>(&self, hasher: &mut U) {
23                self.0.fingerprint(hasher);
24            }
25        }
26    };
27}
28
29macro_rules! impl_deref {
30    ($type: ty) => {
31        impl<T: Fingerprint + ?Sized> Fingerprint for $type {
32            #[inline(always)]
33            fn fingerprint<U: Update>(&self, hasher: &mut U) {
34                (**self).fingerprint(hasher);
35            }
36        }
37    };
38}
39
40impl_deref!(&T);
41impl_deref!(&mut T);
42#[cfg(feature = "alloc")]
43impl_deref!(alloc::boxed::Box<T>);
44#[cfg(feature = "alloc")]
45impl_deref!(alloc::rc::Rc<T>);
46#[cfg(feature = "alloc")]
47impl_deref!(alloc::sync::Arc<T>);
48
49#[cfg(feature = "alloc")]
50impl<'a, T: Fingerprint + Clone> Fingerprint for alloc::borrow::Cow<'a, T> {
51    #[inline(always)]
52    fn fingerprint<U: Update>(&self, hasher: &mut U) {
53        (**self).fingerprint(hasher);
54    }
55}
56
57impl<T: Fingerprint + Copy> Fingerprint for core::cell::Cell<T> {
58    #[inline(always)]
59    fn fingerprint<U: Update>(&self, hasher: &mut U) {
60        self.get().fingerprint(hasher);
61    }
62}
63
64macro_rules! impl_primitive {
65    ($type: ty) => {
66        impl Fingerprint for $type {
67            #[inline(always)]
68            fn fingerprint<U: Update>(&self, hasher: &mut U) {
69                hasher.update(&self.to_le_bytes());
70            }
71        }
72    };
73}
74
75impl_primitive!(i8);
76impl_primitive!(i16);
77impl_primitive!(i32);
78impl_primitive!(i64);
79impl_primitive!(i128);
80impl_primitive!(u8);
81impl_primitive!(u16);
82impl_primitive!(u32);
83impl_primitive!(u64);
84impl_primitive!(u128);
85impl_primitive!(f32);
86impl_primitive!(f64);
87
88macro_rules! impl_through_cast {
89    ($type: ty, $cast: ty) => {
90        impl Fingerprint for $type {
91            #[inline(always)]
92            fn fingerprint<U: Update>(&self, hasher: &mut U) {
93                (*self as $cast).fingerprint(hasher);
94            }
95        }
96    };
97}
98
99impl_through_cast!(char, u32);
100impl_through_cast!(bool, u8);
101
102macro_rules! impl_through_from {
103    ($type: ty, $into: ty) => {
104        impl Fingerprint for $type {
105            #[inline(always)]
106            fn fingerprint<U: Update>(&self, hasher: &mut U) {
107                <$into>::from(*self).fingerprint(hasher);
108            }
109        }
110    };
111}
112
113impl_through_from!(core::num::NonZeroI8, i8);
114impl_through_from!(core::num::NonZeroI16, i16);
115impl_through_from!(core::num::NonZeroI32, i32);
116impl_through_from!(core::num::NonZeroI64, i64);
117impl_through_from!(core::num::NonZeroI128, i128);
118impl_through_from!(core::num::NonZeroIsize, isize);
119impl_through_from!(core::num::NonZeroU8, u8);
120impl_through_from!(core::num::NonZeroU16, u16);
121impl_through_from!(core::num::NonZeroU32, u32);
122impl_through_from!(core::num::NonZeroU64, u64);
123impl_through_from!(core::num::NonZeroU128, u128);
124impl_through_from!(core::num::NonZeroUsize, usize);
125
126impl_method!(
127    core::sync::atomic::AtomicBool,
128    load(core::sync::atomic::Ordering::Relaxed)
129);
130impl_method!(
131    core::sync::atomic::AtomicI8,
132    load(core::sync::atomic::Ordering::Relaxed)
133);
134impl_method!(
135    core::sync::atomic::AtomicI16,
136    load(core::sync::atomic::Ordering::Relaxed)
137);
138impl_method!(
139    core::sync::atomic::AtomicI32,
140    load(core::sync::atomic::Ordering::Relaxed)
141);
142impl_method!(
143    core::sync::atomic::AtomicI64,
144    load(core::sync::atomic::Ordering::Relaxed)
145);
146impl_method!(
147    core::sync::atomic::AtomicIsize,
148    load(core::sync::atomic::Ordering::Relaxed)
149);
150impl_method!(
151    core::sync::atomic::AtomicU8,
152    load(core::sync::atomic::Ordering::Relaxed)
153);
154impl_method!(
155    core::sync::atomic::AtomicU16,
156    load(core::sync::atomic::Ordering::Relaxed)
157);
158impl_method!(
159    core::sync::atomic::AtomicU32,
160    load(core::sync::atomic::Ordering::Relaxed)
161);
162impl_method!(
163    core::sync::atomic::AtomicU64,
164    load(core::sync::atomic::Ordering::Relaxed)
165);
166impl_method!(
167    core::sync::atomic::AtomicUsize,
168    load(core::sync::atomic::Ordering::Relaxed)
169);
170
171impl Fingerprint for usize {
172    // Encodes usize as a variable size integer.
173    // This makes the hash consistant not only between 32 and 64-bit architectures, but also among
174    // as of yet uninvented architectures with even larger pointers. The encoding is based on
175    // protobuf varints. Each byte contains a base 128 digit, with the MSB being a continuation
176    // flag. The digits are arranged in little endian order. See the protobuf documentation or
177    // https://en.wikipedia.org/wiki/Variable-length_quantity for more details.
178    #[inline]
179    fn fingerprint<U: Update>(&self, hasher: &mut U) {
180        let mut rest = *self;
181
182        loop {
183            let digit = rest & ((1 << 7) - 1);
184            rest >>= 7;
185
186            let digit = digit as u8;
187            let digit = digit | if rest > 0 { 1 << 7 } else { 0 };
188
189            digit.fingerprint(hasher);
190
191            if rest == 0 {
192                break;
193            }
194        }
195    }
196}
197
198impl Fingerprint for isize {
199    // Encodes isize as a variable size integer.
200    // This encoding as also based on protobuf varints. It uses "zigzag" encoding, which encodes
201    // 0 to 0, -1 to 1, 1 to 2, -2 to 3, 2 to 4 and so on. See the protobuf documentation or
202    // https://en.wikipedia.org/wiki/Variable-length_quantity#Zigzag_encoding for more details.
203    #[inline]
204    fn fingerprint<U: Update>(&self, hasher: &mut U) {
205        let value = *self;
206        let value = (value << 1) ^ (value >> (isize::BITS - 1));
207        let value = value as usize;
208        value.fingerprint(hasher);
209    }
210}
211
212impl<T: Fingerprint, const N: usize> Fingerprint for [T; N] {
213    #[inline(always)]
214    fn fingerprint<U: Update>(&self, hasher: &mut U) {
215        for i in self {
216            i.fingerprint(hasher);
217        }
218    }
219}
220
221macro_rules! impl_tuple {
222    ($($num: tt: $name: ident)*) => {
223        impl<$($name: Fingerprint),*> Fingerprint for ($($name,)*) {
224            #[inline(always)]
225            #[allow(unused_variables)] // In case of the empty stuct
226            fn fingerprint<U: Update>(&self, hasher: &mut U) {
227                $(
228                    self.$num.fingerprint(hasher);
229                )*
230            }
231        }
232    };
233}
234
235impl_tuple!();
236impl_tuple!(0: T0);
237impl_tuple!(0: T0 1: T1);
238impl_tuple!(0: T0 1: T1 2: T2);
239impl_tuple!(0: T0 1: T1 2: T2 3: T3);
240impl_tuple!(0: T0 1: T1 2: T2 3: T3 4: T4);
241impl_tuple!(0: T0 1: T1 2: T2 3: T3 4: T4 5: T5);
242impl_tuple!(0: T0 1: T1 2: T2 3: T3 4: T4 5: T5 6: T6);
243impl_tuple!(0: T0 1: T1 2: T2 3: T3 4: T4 5: T5 6: T6 7: T7);
244impl_tuple!(0: T0 1: T1 2: T2 3: T3 4: T4 5: T5 6: T6 7: T7 8: T8);
245impl_tuple!(0: T0 1: T1 2: T2 3: T3 4: T4 5: T5 6: T6 7: T7 8: T8 9: T9);
246impl_tuple!(0: T0 1: T1 2: T2 3: T3 4: T4 5: T5 6: T6 7: T7 8: T8 9: T9 10: T10);
247impl_tuple!(0: T0 1: T1 2: T2 3: T3 4: T4 5: T5 6: T6 7: T7 8: T8 9: T9 10: T10 11: T11);
248impl_tuple!(0: T0 1: T1 2: T2 3: T3 4: T4 5: T5 6: T6 7: T7 8: T8 9: T9 10: T10 11: T11 12: T12);
249impl_tuple!(0: T0 1: T1 2: T2 3: T3 4: T4 5: T5 6: T6 7: T7 8: T8 9: T9 10: T10 11: T11 12: T12 13: T13);
250impl_tuple!(0: T0 1: T1 2: T2 3: T3 4: T4 5: T5 6: T6 7: T7 8: T8 9: T9 10: T10 11: T11 12: T12 13: T13 14: T14);
251impl_tuple!(0: T0 1: T1 2: T2 3: T3 4: T4 5: T5 6: T6 7: T7 8: T8 9: T9 10: T10 11: T11 12: T12 13: T13 14: T14 15: T15);
252
253macro_rules! impl_string_like {
254    ($type: ty) => {
255        impl Fingerprint for $type {
256            #[inline]
257            fn fingerprint<U: Update>(&self, hasher: &mut U) {
258                self.len().fingerprint(hasher);
259                hasher.update(self.as_bytes());
260            }
261        }
262    };
263}
264
265impl_string_like!(str);
266#[cfg(feature = "alloc")]
267impl_string_like!(alloc::string::String);
268
269#[cfg(feature = "std")]
270macro_rules! impl_cstring_like {
271    ($type: ty) => {
272        impl Fingerprint for $type {
273            #[inline]
274            fn fingerprint<U: Update>(&self, hasher: &mut U) {
275                hasher.update(self.to_bytes_with_nul());
276            }
277        }
278    };
279}
280
281#[cfg(feature = "std")]
282impl_cstring_like!(std::ffi::CStr);
283#[cfg(feature = "std")]
284impl_cstring_like!(std::ffi::CString);
285
286impl<T: Fingerprint> Fingerprint for Option<T> {
287    #[inline]
288    fn fingerprint<U: Update>(&self, hasher: &mut U) {
289        match self {
290            Some(value) => {
291                0u8.fingerprint(hasher);
292                value.fingerprint(hasher);
293            }
294            None => 1u8.fingerprint(hasher),
295        }
296    }
297}
298
299impl<T: Fingerprint, E: Fingerprint> Fingerprint for Result<T, E> {
300    #[inline]
301    fn fingerprint<U: Update>(&self, hasher: &mut U) {
302        match self {
303            Ok(value) => {
304                0u8.fingerprint(hasher);
305                value.fingerprint(hasher);
306            }
307            Err(value) => {
308                1u8.fingerprint(hasher);
309                value.fingerprint(hasher);
310            }
311        }
312    }
313}
314
315impl<T: ?Sized> Fingerprint for core::marker::PhantomData<T> {
316    #[inline]
317    fn fingerprint<U: Update>(&self, _hasher: &mut U) {}
318}
319
320macro_rules! impl_ordered_seq {
321    ($type: ty $(,$bound: tt)?) => {
322        impl<T: Fingerprint $(+ $bound)?> Fingerprint for $type {
323            #[inline]
324            fn fingerprint<U: Update>(&self, hasher: &mut U) {
325                self.len().fingerprint(hasher);
326
327                for element in self.iter() {
328                    element.fingerprint(hasher);
329                }
330            }
331        }
332    };
333}
334
335impl_ordered_seq!([T]);
336#[cfg(feature = "alloc")]
337impl_ordered_seq!(alloc::vec::Vec<T>);
338#[cfg(feature = "alloc")]
339impl_ordered_seq!(alloc::collections::BTreeSet<T>, Ord);
340#[cfg(feature = "alloc")]
341impl_ordered_seq!(alloc::collections::LinkedList<T>);
342#[cfg(feature = "alloc")]
343impl_ordered_seq!(alloc::collections::VecDeque<T>);
344
345#[cfg(feature = "alloc")]
346macro_rules! impl_unordered_seq {
347    ($type: ty $(,$bound: tt)*) => {
348        impl<T: Fingerprint + Ord $(+ $bound)*> Fingerprint for $type {
349            #[inline]
350            fn fingerprint<U: Update>(&self, hasher: &mut U) {
351                let mut vec: alloc::vec::Vec<&T> = self.iter().collect();
352                vec.sort();
353
354                vec.fingerprint(hasher);
355            }
356        }
357    };
358}
359
360#[cfg(feature = "alloc")]
361impl_unordered_seq!(alloc::collections::BinaryHeap<T>);
362#[cfg(feature = "std")]
363impl_unordered_seq!(std::collections::HashSet<T>, Eq, Hash);
364
365#[cfg(feature = "alloc")]
366impl<K: Fingerprint + Ord, V: Fingerprint> Fingerprint for alloc::collections::BTreeMap<K, V> {
367    #[inline]
368    fn fingerprint<U: Update>(&self, hasher: &mut U) {
369        self.len().fingerprint(hasher);
370
371        for element in self.iter() {
372            element.fingerprint(hasher);
373        }
374    }
375}
376
377#[cfg(feature = "std")]
378impl<K: Fingerprint + Ord + Eq + Hash, V: Fingerprint> Fingerprint
379    for std::collections::HashMap<K, V>
380{
381    #[inline]
382    fn fingerprint<U: Update>(&self, hasher: &mut U) {
383        let mut vec: alloc::vec::Vec<(&K, &V)> = self.iter().collect();
384        vec.sort_by_key(|t| t.0);
385
386        vec.fingerprint(hasher);
387    }
388}
389
390impl<T: Fingerprint> Fingerprint for core::ops::Range<T> {
391    #[inline]
392    fn fingerprint<U: Update>(&self, hasher: &mut U) {
393        self.start.fingerprint(hasher);
394        self.end.fingerprint(hasher);
395    }
396}
397
398impl<T: Fingerprint> Fingerprint for core::ops::RangeInclusive<T> {
399    #[inline]
400    fn fingerprint<U: Update>(&self, hasher: &mut U) {
401        self.start().fingerprint(hasher);
402        self.end().fingerprint(hasher);
403    }
404}
405
406impl<T: Fingerprint> Fingerprint for core::ops::Bound<T> {
407    #[inline]
408    fn fingerprint<U: Update>(&self, hasher: &mut U) {
409        match self {
410            core::ops::Bound::Included(bound) => {
411                0u8.fingerprint(hasher);
412                bound.fingerprint(hasher);
413            }
414            core::ops::Bound::Excluded(bound) => {
415                1u8.fingerprint(hasher);
416                bound.fingerprint(hasher);
417            }
418            core::ops::Bound::Unbounded => {
419                2u8.fingerprint(hasher);
420            }
421        }
422    }
423}
424
425impl_method!(core::time::Duration, as_nanos());
426
427#[cfg(all(feature = "std", feature = "os"))]
428impl Fingerprint for std::time::SystemTime {
429    #[inline]
430    fn fingerprint<U: Update>(&self, hasher: &mut U) {
431        match self.duration_since(std::time::SystemTime::UNIX_EPOCH) {
432            Ok(duration) => {
433                0u8.fingerprint(hasher);
434                duration.fingerprint(hasher);
435            }
436            Err(error) => {
437                1u8.fingerprint(hasher);
438                error.duration().fingerprint(hasher);
439            }
440        }
441    }
442}
443
444#[cfg(feature = "std")]
445impl_method!(std::net::Ipv4Addr, octets());
446#[cfg(feature = "std")]
447impl_method!(std::net::Ipv6Addr, octets());
448
449#[cfg(feature = "std")]
450impl Fingerprint for std::net::IpAddr {
451    #[inline]
452    fn fingerprint<U: Update>(&self, hasher: &mut U) {
453        match self {
454            std::net::IpAddr::V4(address) => {
455                4u8.fingerprint(hasher);
456                address.fingerprint(hasher);
457            }
458            std::net::IpAddr::V6(address) => {
459                6u8.fingerprint(hasher);
460                address.fingerprint(hasher);
461            }
462        }
463    }
464}
465
466#[cfg(feature = "std")]
467impl Fingerprint for std::net::SocketAddrV4 {
468    #[inline]
469    fn fingerprint<U: Update>(&self, hasher: &mut U) {
470        self.ip().fingerprint(hasher);
471        self.port().fingerprint(hasher);
472    }
473}
474
475#[cfg(feature = "std")]
476impl Fingerprint for std::net::SocketAddrV6 {
477    #[inline]
478    fn fingerprint<U: Update>(&self, hasher: &mut U) {
479        self.ip().fingerprint(hasher);
480        self.port().fingerprint(hasher);
481        self.flowinfo().fingerprint(hasher);
482        self.scope_id().fingerprint(hasher);
483    }
484}
485
486#[cfg(feature = "std")]
487impl Fingerprint for std::net::SocketAddr {
488    #[inline]
489    fn fingerprint<U: Update>(&self, hasher: &mut U) {
490        match self {
491            std::net::SocketAddr::V4(address) => {
492                4u8.fingerprint(hasher);
493                address.fingerprint(hasher);
494            }
495            std::net::SocketAddr::V6(address) => {
496                6u8.fingerprint(hasher);
497                address.fingerprint(hasher);
498            }
499        }
500    }
501}
502
503impl_inner!(core::num::Wrapping<T>);
504impl_inner!(core::cmp::Reverse<T>);