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