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}