Coverage Report

Created: 2026-02-26 06:30

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/ahash-0.8.12/src/specialize.rs
Line
Count
Source
1
use crate::RandomState;
2
use core::hash::BuildHasher;
3
use core::hash::Hash;
4
use core::hash::Hasher;
5
6
#[cfg(not(feature = "std"))]
7
extern crate alloc;
8
#[cfg(feature = "std")]
9
extern crate std as alloc;
10
11
#[cfg(specialize)]
12
use alloc::string::String;
13
#[cfg(specialize)]
14
use alloc::vec::Vec;
15
16
/// Provides a way to get an optimized hasher for a given data type.
17
/// Rather than using a Hasher generically which can hash any value, this provides a way to get a specialized hash
18
/// for a specific type. So this may be faster for primitive types.
19
pub(crate) trait CallHasher {
20
    fn get_hash<H: Hash + ?Sized>(value: &H, random_state: &RandomState) -> u64;
21
}
22
23
#[cfg(not(specialize))]
24
impl<T> CallHasher for T
25
where
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)]
37
impl<T> CallHasher for T
38
where
39
    T: Hash + ?Sized,
40
{
41
    #[inline]
42
5.13M
    default fn get_hash<H: Hash + ?Sized>(value: &H, random_state: &RandomState) -> u64 {
43
5.13M
        let mut hasher = random_state.build_hasher();
44
5.13M
        value.hash(&mut hasher);
45
5.13M
        hasher.finish()
46
5.13M
    }
<&str as ahash::specialize::CallHasher>::get_hash::<&str>
Line
Count
Source
42
249k
    default fn get_hash<H: Hash + ?Sized>(value: &H, random_state: &RandomState) -> u64 {
43
249k
        let mut hasher = random_state.build_hasher();
44
249k
        value.hash(&mut hasher);
45
249k
        hasher.finish()
46
249k
    }
<&alloc::string::String as ahash::specialize::CallHasher>::get_hash::<&alloc::string::String>
Line
Count
Source
42
4.88M
    default fn get_hash<H: Hash + ?Sized>(value: &H, random_state: &RandomState) -> u64 {
43
4.88M
        let mut hasher = random_state.build_hasher();
44
4.88M
        value.hash(&mut hasher);
45
4.88M
        hasher.finish()
46
4.88M
    }
Unexecuted instantiation: <_ as ahash::specialize::CallHasher>::get_hash::<_>
47
}
48
49
macro_rules! call_hasher_impl_u64 {
50
    ($typ:ty) => {
51
        #[cfg(specialize)]
52
        impl CallHasher for $typ {
53
            #[inline]
54
0
            fn get_hash<H: Hash + ?Sized>(value: &H, random_state: &RandomState) -> u64 {
55
0
                random_state.hash_as_u64(value)
56
0
            }
Unexecuted instantiation: <u8 as ahash::specialize::CallHasher>::get_hash::<_>
Unexecuted instantiation: <u16 as ahash::specialize::CallHasher>::get_hash::<_>
Unexecuted instantiation: <u32 as ahash::specialize::CallHasher>::get_hash::<_>
Unexecuted instantiation: <u64 as ahash::specialize::CallHasher>::get_hash::<_>
Unexecuted instantiation: <i8 as ahash::specialize::CallHasher>::get_hash::<_>
Unexecuted instantiation: <i16 as ahash::specialize::CallHasher>::get_hash::<_>
Unexecuted instantiation: <i32 as ahash::specialize::CallHasher>::get_hash::<_>
Unexecuted instantiation: <i64 as ahash::specialize::CallHasher>::get_hash::<_>
Unexecuted instantiation: <&u8 as ahash::specialize::CallHasher>::get_hash::<_>
Unexecuted instantiation: <&u16 as ahash::specialize::CallHasher>::get_hash::<_>
Unexecuted instantiation: <&u32 as ahash::specialize::CallHasher>::get_hash::<_>
Unexecuted instantiation: <&u64 as ahash::specialize::CallHasher>::get_hash::<_>
Unexecuted instantiation: <&i8 as ahash::specialize::CallHasher>::get_hash::<_>
Unexecuted instantiation: <&i16 as ahash::specialize::CallHasher>::get_hash::<_>
Unexecuted instantiation: <&i32 as ahash::specialize::CallHasher>::get_hash::<_>
Unexecuted instantiation: <&i64 as ahash::specialize::CallHasher>::get_hash::<_>
57
        }
58
    };
59
}
60
call_hasher_impl_u64!(u8);
61
call_hasher_impl_u64!(u16);
62
call_hasher_impl_u64!(u32);
63
call_hasher_impl_u64!(u64);
64
call_hasher_impl_u64!(i8);
65
call_hasher_impl_u64!(i16);
66
call_hasher_impl_u64!(i32);
67
call_hasher_impl_u64!(i64);
68
call_hasher_impl_u64!(&u8);
69
call_hasher_impl_u64!(&u16);
70
call_hasher_impl_u64!(&u32);
71
call_hasher_impl_u64!(&u64);
72
call_hasher_impl_u64!(&i8);
73
call_hasher_impl_u64!(&i16);
74
call_hasher_impl_u64!(&i32);
75
call_hasher_impl_u64!(&i64);
76
77
macro_rules! call_hasher_impl_fixed_length{
78
    ($typ:ty) => {
79
        #[cfg(specialize)]
80
        impl CallHasher for $typ {
81
            #[inline]
82
0
            fn get_hash<H: Hash + ?Sized>(value: &H, random_state: &RandomState) -> u64 {
83
0
                random_state.hash_as_fixed_length(value)
84
0
            }
Unexecuted instantiation: <u128 as ahash::specialize::CallHasher>::get_hash::<_>
Unexecuted instantiation: <i128 as ahash::specialize::CallHasher>::get_hash::<_>
Unexecuted instantiation: <usize as ahash::specialize::CallHasher>::get_hash::<_>
Unexecuted instantiation: <isize as ahash::specialize::CallHasher>::get_hash::<_>
Unexecuted instantiation: <&u128 as ahash::specialize::CallHasher>::get_hash::<_>
Unexecuted instantiation: <&i128 as ahash::specialize::CallHasher>::get_hash::<_>
Unexecuted instantiation: <&usize as ahash::specialize::CallHasher>::get_hash::<_>
Unexecuted instantiation: <&isize as ahash::specialize::CallHasher>::get_hash::<_>
85
        }
86
    };
87
}
88
89
call_hasher_impl_fixed_length!(u128);
90
call_hasher_impl_fixed_length!(i128);
91
call_hasher_impl_fixed_length!(usize);
92
call_hasher_impl_fixed_length!(isize);
93
call_hasher_impl_fixed_length!(&u128);
94
call_hasher_impl_fixed_length!(&i128);
95
call_hasher_impl_fixed_length!(&usize);
96
call_hasher_impl_fixed_length!(&isize);
97
98
#[cfg(specialize)]
99
impl CallHasher for [u8] {
100
    #[inline]
101
0
    fn get_hash<H: Hash + ?Sized>(value: &H, random_state: &RandomState) -> u64 {
102
0
        random_state.hash_as_str(value)
103
0
    }
104
}
105
106
#[cfg(specialize)]
107
impl CallHasher for Vec<u8> {
108
    #[inline]
109
0
    fn get_hash<H: Hash + ?Sized>(value: &H, random_state: &RandomState) -> u64 {
110
0
        random_state.hash_as_str(value)
111
0
    }
112
}
113
114
#[cfg(specialize)]
115
impl CallHasher for str {
116
    #[inline]
117
0
    fn get_hash<H: Hash + ?Sized>(value: &H, random_state: &RandomState) -> u64 {
118
0
        random_state.hash_as_str(value)
119
0
    }
120
}
121
122
#[cfg(all(specialize))]
123
impl CallHasher for String {
124
    #[inline]
125
0
    fn get_hash<H: Hash + ?Sized>(value: &H, random_state: &RandomState) -> u64 {
126
0
        random_state.hash_as_str(value)
127
0
    }
128
}
129
130
#[cfg(test)]
131
mod 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
    /// Tests that some non-trivial transformation takes place.
146
    #[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
}