hud_slice_by_8/crc32c/
hasher.rs

1use crate::crc32c::slice_by_8_with_seed;
2use core::hash::{BuildHasher, BuildHasherDefault, Hasher};
3
4/// Slice-By-8 hasher
5#[derive(Debug, Default)]
6pub struct CRC32CHasher {
7    key: u32,
8}
9
10impl CRC32CHasher {
11    /// Create a new [CRC32CHasher] initiated with a hash key
12    pub fn with_seed(seed: u32) -> CRC32CHasher {
13        CRC32CHasher { key: seed }
14    }
15}
16
17impl Hasher for CRC32CHasher {
18    /// Returns the hash value for the values written so far.
19    ///
20    /// # Example
21    ///
22    /// ```
23    /// use hud_slice_by_8::crc32c::CRC32CHasher;
24    /// use core::hash::Hasher;
25    ///
26    /// let hasher = CRC32CHasher::with_seed(0x4C2750BD);
27    /// assert_eq!(hasher.finish(), 0x4C2750BD);
28    /// ```
29    fn finish(&self) -> u64 {
30        self.key as u64
31    }
32
33    /// Writes some data into the [CRC32CHasher].
34    ///
35    /// # Example
36    ///
37    /// ```
38    /// use hud_slice_by_8::crc32c::CRC32CHasher;
39    /// use core::hash::Hasher;
40    ///
41    /// let mut hasher = CRC32CHasher::default();
42    /// hasher.write(b"hash me!");
43    /// ```
44    fn write(&mut self, bytes: &[u8]) {
45        self.key = slice_by_8_with_seed(bytes, self.key);
46    }
47}
48
49impl BuildHasher for CRC32CHasher {
50    type Hasher = CRC32CHasher;
51
52    /// Creates a new [CRC32CHasher].
53    fn build_hasher(&self) -> Self::Hasher {
54        CRC32CHasher::default()
55    }
56}
57
58/// A builder for default [CRC32CHasher].
59pub type CRC32CBuildHasher = BuildHasherDefault<CRC32CHasher>;
60
61#[cfg(test)]
62mod tests {
63
64    use super::{CRC32CBuildHasher, CRC32CHasher};
65    use crate::crc32c;
66    use core::hash::{BuildHasher, Hasher};
67
68    #[test]
69    fn hasher_default() {
70        let hasher = CRC32CHasher::default();
71        assert_eq!(hasher.finish(), 0);
72    }
73
74    #[test]
75    fn hasher_with_seed() {
76        let hasher = CRC32CHasher::with_seed(0x9B9BEFFB);
77        assert_eq!(hasher.finish(), 0x9B9BEFFB);
78    }
79
80    #[test]
81    fn build_hasher() {
82        let build_hasher = CRC32CHasher::default();
83        let mut hasher = build_hasher.build_hasher();
84        hasher.write(b"abcdefghijklmnopqrstuvwxyz");
85        assert_eq!(hasher.finish(), 0x9EE6EF25);
86    }
87
88    #[test]
89    fn build_hasher_results_are_coherent_with_free_function() {
90        let build_hasher = CRC32CHasher::default();
91        let mut hasher = build_hasher.build_hasher();
92
93        const HASH_ME: &[u8] = b"abcdefghijklmnopqrstuvwxyz";
94
95        // First hash is equivalent to city_hash_64 with no seed
96        let hash_free_function = crc32c::slice_by_8(HASH_ME);
97        hasher.write(HASH_ME);
98        assert_eq!(hasher.finish(), hash_free_function as u64);
99
100        // Second hash is equivalent to city_hash_64_with_seed with seed that is hash key of the first hash
101        let hash_free_function = crc32c::slice_by_8_with_seed(HASH_ME, hash_free_function);
102        hasher.write(HASH_ME);
103        assert_eq!(hasher.finish(), hash_free_function as u64);
104    }
105
106    #[test]
107    fn hasher_is_usable_in_std_collections() {
108        extern crate std;
109        use std::collections::HashMap;
110        const HASH_ME: &str = "hash me!";
111        const VALUE: &str = "Hi";
112
113        let mut map = HashMap::with_hasher(CRC32CBuildHasher::default());
114        map.insert(HASH_ME, VALUE);
115        assert_eq!(map.get(&HASH_ME), Some(&VALUE));
116    }
117}