1use crate::RandomState;
2use core::hash::BuildHasher;
3use core::hash::Hash;
4use core::hash::Hasher;
5
6#[cfg(not(feature = "std"))]
7extern crate alloc;
8#[cfg(feature = "std")]
9extern crate std as alloc;
10
11#[cfg(specialize)]
12use alloc::string::String;
13#[cfg(specialize)]
14use alloc::vec::Vec;
15
16pub(crate) trait CallHasher {
20 fn get_hash<H: Hash + ?Sized>(value: &H, random_state: &RandomState) -> u64;
21}
22
23#[cfg(not(specialize))]
24impl<T> CallHasher for T
25where
26 T: Hash + ?Sized,
27{
28 #[inline]
29 fn get_hash<H: Hash + ?Sized>(value: &H, random_state: &RandomState) -> u64 {
30 let mut hasher = random_state.build_hasher();
31 value.hash(&mut hasher);
32 hasher.finish()
33 }
34}
35
36#[cfg(specialize)]
37impl<T> CallHasher for T
38where
39 T: Hash + ?Sized,
40{
41 #[inline]
42 default fn get_hash<H: Hash + ?Sized>(value: &H, random_state: &RandomState) -> u64 {
43 let mut hasher = random_state.build_hasher();
44 value.hash(&mut hasher);
45 hasher.finish()
46 }
47}
48
49macro_rules! call_hasher_impl_u64 {
50 ($typ:ty) => {
51 #[cfg(specialize)]
52 impl CallHasher for $typ {
53 #[inline]
54 fn get_hash<H: Hash + ?Sized>(value: &H, random_state: &RandomState) -> u64 {
55 random_state.hash_as_u64(value)
56 }
57 }
58 };
59}
60call_hasher_impl_u64!(u8);
61call_hasher_impl_u64!(u16);
62call_hasher_impl_u64!(u32);
63call_hasher_impl_u64!(u64);
64call_hasher_impl_u64!(i8);
65call_hasher_impl_u64!(i16);
66call_hasher_impl_u64!(i32);
67call_hasher_impl_u64!(i64);
68call_hasher_impl_u64!(&u8);
69call_hasher_impl_u64!(&u16);
70call_hasher_impl_u64!(&u32);
71call_hasher_impl_u64!(&u64);
72call_hasher_impl_u64!(&i8);
73call_hasher_impl_u64!(&i16);
74call_hasher_impl_u64!(&i32);
75call_hasher_impl_u64!(&i64);
76
77macro_rules! call_hasher_impl_fixed_length{
78 ($typ:ty) => {
79 #[cfg(specialize)]
80 impl CallHasher for $typ {
81 #[inline]
82 fn get_hash<H: Hash + ?Sized>(value: &H, random_state: &RandomState) -> u64 {
83 random_state.hash_as_fixed_length(value)
84 }
85 }
86 };
87}
88
89call_hasher_impl_fixed_length!(u128);
90call_hasher_impl_fixed_length!(i128);
91call_hasher_impl_fixed_length!(usize);
92call_hasher_impl_fixed_length!(isize);
93call_hasher_impl_fixed_length!(&u128);
94call_hasher_impl_fixed_length!(&i128);
95call_hasher_impl_fixed_length!(&usize);
96call_hasher_impl_fixed_length!(&isize);
97
98#[cfg(specialize)]
99impl CallHasher for [u8] {
100 #[inline]
101 fn get_hash<H: Hash + ?Sized>(value: &H, random_state: &RandomState) -> u64 {
102 random_state.hash_as_str(value)
103 }
104}
105
106#[cfg(specialize)]
107impl CallHasher for Vec<u8> {
108 #[inline]
109 fn get_hash<H: Hash + ?Sized>(value: &H, random_state: &RandomState) -> u64 {
110 random_state.hash_as_str(value)
111 }
112}
113
114#[cfg(specialize)]
115impl CallHasher for str {
116 #[inline]
117 fn get_hash<H: Hash + ?Sized>(value: &H, random_state: &RandomState) -> u64 {
118 random_state.hash_as_str(value)
119 }
120}
121
122#[cfg(all(specialize))]
123impl CallHasher for String {
124 #[inline]
125 fn get_hash<H: Hash + ?Sized>(value: &H, random_state: &RandomState) -> u64 {
126 random_state.hash_as_str(value)
127 }
128}
129
130#[cfg(test)]
131mod test {
132 use super::*;
133 use crate::*;
134
135 #[test]
136 #[cfg(specialize)]
137 pub fn test_specialized_invoked() {
138 let build_hasher = RandomState::with_seeds(1, 2, 3, 4);
139 let shortened = u64::get_hash(&0, &build_hasher);
140 let mut hasher = AHasher::new_with_keys(1, 2);
141 0_u64.hash(&mut hasher);
142 assert_ne!(hasher.finish(), shortened);
143 }
144
145 #[test]
147 pub fn test_input_processed() {
148 let build_hasher = RandomState::with_seeds(2, 2, 2, 2);
149 assert_ne!(0, u64::get_hash(&0, &build_hasher));
150 assert_ne!(1, u64::get_hash(&0, &build_hasher));
151 assert_ne!(2, u64::get_hash(&0, &build_hasher));
152 assert_ne!(3, u64::get_hash(&0, &build_hasher));
153 assert_ne!(4, u64::get_hash(&0, &build_hasher));
154 assert_ne!(5, u64::get_hash(&0, &build_hasher));
155
156 assert_ne!(0, u64::get_hash(&1, &build_hasher));
157 assert_ne!(1, u64::get_hash(&1, &build_hasher));
158 assert_ne!(2, u64::get_hash(&1, &build_hasher));
159 assert_ne!(3, u64::get_hash(&1, &build_hasher));
160 assert_ne!(4, u64::get_hash(&1, &build_hasher));
161 assert_ne!(5, u64::get_hash(&1, &build_hasher));
162
163 let xored = u64::get_hash(&0, &build_hasher) ^ u64::get_hash(&1, &build_hasher);
164 assert_ne!(0, xored);
165 assert_ne!(1, xored);
166 assert_ne!(2, xored);
167 assert_ne!(3, xored);
168 assert_ne!(4, xored);
169 assert_ne!(5, xored);
170 }
171
172 #[test]
173 pub fn test_ref_independent() {
174 let build_hasher = RandomState::with_seeds(1, 2, 3, 4);
175 assert_eq!(u8::get_hash(&&1, &build_hasher), u8::get_hash(&1, &build_hasher));
176 assert_eq!(u16::get_hash(&&2, &build_hasher), u16::get_hash(&2, &build_hasher));
177 assert_eq!(u32::get_hash(&&3, &build_hasher), u32::get_hash(&3, &build_hasher));
178 assert_eq!(u64::get_hash(&&4, &build_hasher), u64::get_hash(&4, &build_hasher));
179 assert_eq!(u128::get_hash(&&5, &build_hasher), u128::get_hash(&5, &build_hasher));
180 assert_eq!(
181 str::get_hash(&"test", &build_hasher),
182 str::get_hash("test", &build_hasher)
183 );
184 assert_eq!(
185 str::get_hash(&"test", &build_hasher),
186 String::get_hash(&"test".to_string(), &build_hasher)
187 );
188 #[cfg(specialize)]
189 assert_eq!(
190 str::get_hash(&"test", &build_hasher),
191 <[u8]>::get_hash("test".as_bytes(), &build_hasher)
192 );
193
194 let build_hasher = RandomState::with_seeds(10, 20, 30, 40);
195 assert_eq!(u8::get_hash(&&&1, &build_hasher), u8::get_hash(&1, &build_hasher));
196 assert_eq!(u16::get_hash(&&&2, &build_hasher), u16::get_hash(&2, &build_hasher));
197 assert_eq!(u32::get_hash(&&&3, &build_hasher), u32::get_hash(&3, &build_hasher));
198 assert_eq!(u64::get_hash(&&&4, &build_hasher), u64::get_hash(&4, &build_hasher));
199 assert_eq!(u128::get_hash(&&&5, &build_hasher), u128::get_hash(&5, &build_hasher));
200 assert_eq!(
201 str::get_hash(&&"test", &build_hasher),
202 str::get_hash("test", &build_hasher)
203 );
204 assert_eq!(
205 str::get_hash(&&"test", &build_hasher),
206 String::get_hash(&"test".to_string(), &build_hasher)
207 );
208 #[cfg(specialize)]
209 assert_eq!(
210 str::get_hash(&&"test", &build_hasher),
211 <[u8]>::get_hash(&"test".to_string().into_bytes(), &build_hasher)
212 );
213 }
214}