1 #[cfg(feature = "specialize")]
2 use crate::HasherExt;
3 use core::hash::Hash;
4 use core::hash::Hasher;
5 
6 /// Provides a way to get an optimized hasher for a given data type.
7 /// Rather than using a Hasher generically which can hash any value, this provides a way to get a specialized hash
8 /// for a specific type. So this may be faster for primitive types. It does however consume the hasher in the process.
9 /// #Example
10 /// ```
11 /// use std::hash::BuildHasher;
12 /// use ahash::RandomState;
13 /// use ahash::CallHasher;
14 ///
15 /// let hash_builder = RandomState::new();
16 /// //...
17 /// let value = 17;
18 /// let hash = value.get_hash(hash_builder.build_hasher());
19 /// ```
20 pub trait CallHasher: Hash {
get_hash<H: Hasher>(&self, hasher: H) -> u6421     fn get_hash<H: Hasher>(&self, hasher: H) -> u64;
22 }
23 
24 #[cfg(not(feature = "specialize"))]
25 impl<T> CallHasher for T
26 where
27     T: Hash,
28 {
29     #[inline]
get_hash<H: Hasher>(&self, mut hasher: H) -> u6430     fn get_hash<H: Hasher>(&self, mut hasher: H) -> u64 {
31         self.hash(&mut hasher);
32         hasher.finish()
33     }
34 }
35 
36 #[cfg(feature = "specialize")]
37 impl<T> CallHasher for T
38 where
39     T: Hash,
40 {
41     #[inline]
get_hash<H: Hasher>(&self, mut hasher: H) -> u6442     default fn get_hash<H: Hasher>(&self, mut hasher: H) -> u64 {
43         self.hash(&mut hasher);
44         hasher.finish()
45     }
46 }
47 
48 macro_rules! call_hasher_impl {
49     ($typ:ty) => {
50         #[cfg(feature = "specialize")]
51         impl CallHasher for $typ {
52             #[inline]
53             fn get_hash<H: Hasher>(&self, hasher: H) -> u64 {
54                 hasher.hash_u64(*self as u64)
55             }
56         }
57     };
58 }
59 call_hasher_impl!(u8);
60 call_hasher_impl!(u16);
61 call_hasher_impl!(u32);
62 call_hasher_impl!(u64);
63 call_hasher_impl!(i8);
64 call_hasher_impl!(i16);
65 call_hasher_impl!(i32);
66 call_hasher_impl!(i64);
67 
68 #[cfg(feature = "specialize")]
69 impl CallHasher for u128 {
70     #[inline]
get_hash<H: Hasher>(&self, mut hasher: H) -> u6471     fn get_hash<H: Hasher>(&self, mut hasher: H) -> u64 {
72         hasher.write_u128(*self);
73         hasher.short_finish()
74     }
75 }
76 
77 #[cfg(feature = "specialize")]
78 impl CallHasher for i128 {
79     #[inline]
get_hash<H: Hasher>(&self, mut hasher: H) -> u6480     fn get_hash<H: Hasher>(&self, mut hasher: H) -> u64 {
81         hasher.write_u128(*self as u128);
82         hasher.short_finish()
83     }
84 }
85 
86 #[cfg(feature = "specialize")]
87 impl CallHasher for [u8] {
88     #[inline]
get_hash<H: Hasher>(&self, mut hasher: H) -> u6489     fn get_hash<H: Hasher>(&self, mut hasher: H) -> u64 {
90         hasher.write(self);
91         hasher.finish()
92     }
93 }
94 
95 #[cfg(all(feature = "specialize", feature = "std"))]
96 impl CallHasher for Vec<u8> {
97     #[inline]
get_hash<H: Hasher>(&self, mut hasher: H) -> u6498     fn get_hash<H: Hasher>(&self, mut hasher: H) -> u64 {
99         hasher.write(self);
100         hasher.finish()
101     }
102 }
103 
104 #[cfg(feature = "specialize")]
105 impl CallHasher for str {
106     #[inline]
get_hash<H: Hasher>(&self, mut hasher: H) -> u64107     fn get_hash<H: Hasher>(&self, mut hasher: H) -> u64 {
108         hasher.write(self.as_bytes());
109         hasher.finish()
110     }
111 }
112 
113 #[cfg(all(feature = "specialize", feature = "std"))]
114 impl CallHasher for String {
115     #[inline]
get_hash<H: Hasher>(&self, mut hasher: H) -> u64116     fn get_hash<H: Hasher>(&self, mut hasher: H) -> u64 {
117         hasher.write(self.as_bytes());
118         hasher.finish()
119     }
120 }
121 
122 #[cfg(test)]
123 mod test {
124     use super::*;
125     use crate::*;
126 
127     #[test]
128     #[cfg(feature = "specialize")]
test_specialized_invoked()129     pub fn test_specialized_invoked() {
130         let shortened = 0_u64.get_hash(AHasher::new_with_keys(1, 2));
131         let mut hasher = AHasher::new_with_keys(1, 2);
132         0_u64.hash(&mut hasher);
133         assert_ne!(hasher.finish(), shortened);
134     }
135 
136     /// Tests that some non-trivial transformation takes place.
137     #[test]
test_input_processed()138     pub fn test_input_processed() {
139         let hasher = || AHasher::new_with_keys(3, 2);
140         assert_ne!(0, 0_u64.get_hash(hasher()));
141         assert_ne!(1, 0_u64.get_hash(hasher()));
142         assert_ne!(2, 0_u64.get_hash(hasher()));
143         assert_ne!(3, 0_u64.get_hash(hasher()));
144         assert_ne!(4, 0_u64.get_hash(hasher()));
145         assert_ne!(5, 0_u64.get_hash(hasher()));
146 
147         assert_ne!(0, 1_u64.get_hash(hasher()));
148         assert_ne!(1, 1_u64.get_hash(hasher()));
149         assert_ne!(2, 1_u64.get_hash(hasher()));
150         assert_ne!(3, 1_u64.get_hash(hasher()));
151         assert_ne!(4, 1_u64.get_hash(hasher()));
152         assert_ne!(5, 1_u64.get_hash(hasher()));
153 
154         let xored = 0_u64.get_hash(hasher()) ^ 1_u64.get_hash(hasher());
155         assert_ne!(0, xored);
156         assert_ne!(1, xored);
157         assert_ne!(2, xored);
158         assert_ne!(3, xored);
159         assert_ne!(4, xored);
160         assert_ne!(5, xored);
161     }
162 }
163