rapidhash/rapid_hasher.rs
1use core::hash::Hasher;
2use crate::rapid_const::{RAPID_SEED};
3use crate::RapidInlineHasher;
4
5/// A [Hasher] trait compatible hasher that uses the [rapidhash](https://github.com/Nicoshev/rapidhash) algorithm.
6///
7/// See [RapidInlineHasher] for an `#[inline(always)]` version of this hasher, which can deliver
8/// speed improvements of around 30% when hashing complex objects.
9///
10/// See [RapidHashBuilder] for usage with [std::collections::HashMap].
11///
12/// # Example
13/// ```
14/// use std::hash::Hasher;
15/// use rapidhash::RapidHasher;
16///
17/// let mut hasher = RapidHasher::default();
18/// hasher.write(b"hello world");
19/// let hash = hasher.finish();
20/// ```
21#[derive(Copy, Clone, Eq, PartialEq)]
22pub struct RapidHasher(RapidInlineHasher);
23
24/// A [std::hash::BuildHasher] trait compatible hasher that uses the [RapidHasher] algorithm.
25///
26/// This is an alias for [`std::hash::BuildHasherDefault<RapidHasher>`] with a static seed.
27///
28/// See [RapidInlineHasher] for an `#[inline(always)]` version of this hasher, which can deliver
29/// speed improvements of around 30% when hashing complex objects.
30///
31/// See [crate::RapidRandomState] can be used instead for a
32/// [std::hash::BuildHasher] that initialises with a random seed.
33///
34/// # Example
35/// ```
36/// use std::collections::HashMap;
37/// use std::hash::Hasher;
38/// use rapidhash::RapidBuildHasher;
39///
40/// let mut map = HashMap::with_hasher(RapidBuildHasher::default());
41/// map.insert(42, "the answer");
42/// ```
43pub type RapidBuildHasher = core::hash::BuildHasherDefault<RapidHasher>;
44
45/// Deprecated and renamed to [RapidBuildHasher].
46#[deprecated(since = "1.1.0", note = "Renamed to `RapidBuildHasher`")]
47#[doc(hidden)]
48pub type RapidHashBuilder = core::hash::BuildHasherDefault<RapidHasher>;
49
50/// A [std::collections::HashMap] type that uses the [RapidBuildHasher] hasher.
51///
52/// See [crate::RapidInlineHashMap] for an `#[inline(always)]` version of this type, which can deliver
53/// speed improvements of around 30% when hashing complex objects.
54///
55/// # Example
56/// ```
57/// use rapidhash::RapidHashMap;
58/// let mut map = RapidHashMap::default();
59/// map.insert(42, "the answer");
60///
61/// // with capacity
62/// let mut map = RapidHashMap::with_capacity_and_hasher(10, Default::default());
63/// map.insert(42, "the answer");
64/// ```
65#[cfg(any(feature = "std", docsrs))]
66pub type RapidHashMap<K, V> = std::collections::HashMap<K, V, RapidBuildHasher>;
67
68/// A [std::collections::HashSet] type that uses the [RapidBuildHasher] hasher.
69///
70/// See [crate::RapidInlineHashSet] for an `#[inline(always)]` version of this type, which can
71/// deliver speed improvements of around 30% when hashing complex objects.
72///
73/// # Example
74/// ```
75/// use rapidhash::RapidHashSet;
76/// let mut set = RapidHashSet::default();
77/// set.insert("the answer");
78///
79/// // with capacity
80/// let mut set = RapidHashSet::with_capacity_and_hasher(10, Default::default());
81/// set.insert("the answer");
82/// ```
83#[cfg(any(feature = "std", docsrs))]
84pub type RapidHashSet<K> = std::collections::HashSet<K, RapidBuildHasher>;
85
86impl RapidHasher {
87 /// Default `RapidHasher` seed.
88 pub const DEFAULT_SEED: u64 = RAPID_SEED;
89
90 /// Create a new [RapidHasher] with a custom seed.
91 #[inline]
92 #[must_use]
93 pub const fn new(seed: u64) -> Self {
94 Self(RapidInlineHasher::new(seed))
95 }
96
97 /// Create a new [RapidHasher] using the default seed.
98 #[inline]
99 #[must_use]
100 pub const fn default_const() -> Self {
101 Self::new(Self::DEFAULT_SEED)
102 }
103
104 /// Const equivalent to [Hasher::write].
105 ///
106 /// # Example
107 /// ```rust
108 /// use rapidhash::RapidHasher;
109 ///
110 /// let hasher = RapidHasher::default_const();
111 /// let hash = hasher
112 /// .write_const(b"some bytes")
113 /// .write_const(b"and some more bytes")
114 /// .finish_const();
115 /// ```
116 #[inline]
117 #[must_use]
118 pub const fn write_const(&self, bytes: &[u8]) -> Self {
119 Self(self.0.write_const(bytes))
120 }
121
122 /// Const equivalent to [Hasher::finish].
123 #[inline]
124 #[must_use]
125 pub const fn finish_const(&self) -> u64 {
126 self.0.finish_const()
127 }
128}
129
130impl Default for RapidHasher {
131 /// Create a new [RapidHasher] with the default seed.
132 ///
133 /// See [crate::RapidRandomState] for a [std::hash::BuildHasher] that initialises with a random
134 /// seed.
135 #[inline]
136 fn default() -> Self {
137 Self::new(RAPID_SEED)
138 }
139}
140
141/// This implementation implements methods for all integer types as the compiler will (hopefully...)
142/// inline and heavily optimize the rapidhash_core for each. Where the bytes length is known the
143/// compiler can make significant optimisations and saves us writing them out by hand.
144impl Hasher for RapidHasher {
145 #[inline]
146 fn finish(&self) -> u64 {
147 self.0.finish_const()
148 }
149
150 /// Write a byte slice to the hasher.
151 #[inline]
152 fn write(&mut self, bytes: &[u8]) {
153 self.0.write(bytes)
154 }
155
156 #[inline]
157 fn write_u8(&mut self, i: u8) {
158 self.0.write_u8(i)
159 }
160
161 #[inline]
162 fn write_u16(&mut self, i: u16) {
163 self.0.write_u16(i)
164 }
165
166 #[inline]
167 fn write_u32(&mut self, i: u32) {
168 self.0.write_u32(i)
169 }
170
171 #[inline]
172 fn write_u64(&mut self, i: u64) {
173 self.0.write_u64(i)
174 }
175
176 #[inline]
177 fn write_u128(&mut self, i: u128) {
178 self.0.write_u128(i)
179 }
180
181 #[inline]
182 fn write_usize(&mut self, i: usize) {
183 self.0.write_usize(i)
184 }
185
186 #[inline]
187 fn write_i8(&mut self, i: i8) {
188 self.0.write_i8(i)
189 }
190
191 #[inline]
192 fn write_i16(&mut self, i: i16) {
193 self.0.write_i16(i)
194 }
195
196 #[inline]
197 fn write_i32(&mut self, i: i32) {
198 self.0.write_i32(i)
199 }
200
201 #[inline]
202 fn write_i64(&mut self, i: i64) {
203 self.0.write_i64(i)
204 }
205
206 #[inline]
207 fn write_i128(&mut self, i: i128) {
208 self.0.write_i128(i)
209 }
210
211 #[inline]
212 fn write_isize(&mut self, i: isize) {
213 self.0.write_isize(i)
214 }
215}
216
217#[cfg(test)]
218mod tests {
219 use super::*;
220
221 #[test]
222 fn test_hasher_write_u64() {
223 let ints = [
224 1234u64,
225 0,
226 1,
227 u64::MAX,
228 u64::MAX - 2385962040453523
229 ];
230
231 for int in ints {
232 let mut hasher = RapidHasher::default();
233 hasher.write(int.to_ne_bytes().as_slice());
234 let a = hasher.finish();
235
236 assert_eq!(int.to_ne_bytes().as_slice().len(), 8);
237
238 let mut hasher = RapidHasher::default();
239 hasher.write_u64(int);
240 let b = hasher.finish();
241
242 assert_eq!(a, b, "Mismatching hash for u64 with input {int}");
243 }
244 }
245}