Skip to main content

osom_lib_hashes/
fnv.rs

1//! Holds the implementation of several variants of Fowler–Noll–Vo hash functions
2//! and their corresponding builders.
3
4#![allow(non_camel_case_types)]
5
6use core::hash::{BuildHasher, Hasher};
7
8use osom_lib_reprc::macros::reprc;
9
10use super::traits::HashFunction;
11
12macro_rules! build_fnv {
13    ( $variant: tt, $underlying_type: tt ) => {
14        ::paste::paste! {
15            #[doc = "The [FNV](https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function) algorithm in version " $variant " with " $underlying_type "bit size."]
16            #[derive(PartialEq, Eq)]
17            #[reprc]
18            #[must_use]
19            pub struct [< FNV $variant _ $underlying_type >] {
20                state: [< u $underlying_type >],
21            }
22
23            impl Default for [< FNV $variant _ $underlying_type >] {
24                #[inline(always)]
25                fn default() -> Self {
26                    Self::new()
27                }
28            }
29
30            impl [< FNV $variant _ $underlying_type >] {
31                #[doc = "Creates a new instance of [`FNV" $variant "_" $underlying_type "`] with the default initial state."]
32                #[inline(always)]
33                pub const fn new() -> Self {
34                    Self {
35                        state: Self::INITIAL,
36                    }
37                }
38
39                #[doc = "Creates a new instance of [`FNV" $variant "_" $underlying_type "`] from seed."]
40                pub const fn with_seed(seed: [< u $underlying_type >]) -> Self {
41                    let seed = seed.to_le_bytes();
42                    let mut result = Self::new();
43                    result.result_const(&seed);
44                    result
45                }
46
47                #[doc = "Returns calculated hash."]
48                #[inline(always)]
49                pub const fn update_const(&self) -> [< u $underlying_type >] {
50                    self.state
51                }
52
53                #[inline(always)]
54                const fn clone_const(&self) -> Self {
55                    Self {
56                        state: self.state,
57                    }
58                }
59            }
60
61            impl Hasher for [< FNV $variant _ $underlying_type >] {
62                #[allow(clippy::cast_possible_truncation)]
63                #[inline(always)]
64                fn finish(&self) -> u64 {
65                    self.update_const() as u64
66                }
67
68                #[inline(always)]
69                fn write(&mut self, bytes: &[u8]) {
70                    self.update(bytes);
71                }
72            }
73
74            impl HashFunction for [< FNV $variant _ $underlying_type >] {
75                type Output = [u8; size_of::<[< u $underlying_type >]>()];
76
77                #[inline(always)]
78                fn update(&mut self, data: impl AsRef<[u8]>) {
79                    self.result_const(data.as_ref())
80                }
81
82                #[inline(always)]
83                fn write_result(&self, output: &mut Self::Output ) {
84                    *output = self.update_const().to_le_bytes();
85                }
86            }
87
88            #[doc = "A standard builder that produces [`FNV" $variant "_" $underlying_type "`] hash with fixed seed."]
89            #[reprc]
90            #[derive(PartialEq, Eq)]
91            #[must_use]
92            pub struct [< FNV $variant _ $underlying_type HasherBuilder >] {
93                inner: [< FNV $variant _ $underlying_type >],
94            }
95
96            impl [< FNV $variant _ $underlying_type HasherBuilder >] {
97                #[doc = "Creates new [`FNV" $variant "_" $underlying_type "HasherBuilder`]."]
98                #[inline(always)]
99                pub const fn new() -> Self {
100                    Self {
101                        inner: [< FNV $variant _ $underlying_type >]::new(),
102                    }
103                }
104
105                #[doc = "Creates new [`FNV" $variant "_" $underlying_type "HasherBuilder`] with a fixed seed,"]
106                #[doc = "which will be used to initialize the hash function."]
107                #[inline(always)]
108                pub const fn with_seed(seed: [< u $underlying_type >]) -> Self {
109                    Self {
110                        inner: [< FNV $variant _ $underlying_type >]::with_seed(seed),
111                    }
112                }
113
114
115                #[doc = "Creates new [`FNV" $variant "_" $underlying_type "`] instance."]
116                #[inline(always)]
117                pub const fn create_hasher(&self) -> [< FNV $variant _ $underlying_type >] {
118                    self.inner.clone_const()
119                }
120            }
121
122            impl Default for [< FNV $variant _ $underlying_type HasherBuilder >] {
123                #[inline(always)]
124                fn default() -> Self {
125                    Self::new()
126                }
127            }
128
129            impl Clone for [< FNV $variant _ $underlying_type HasherBuilder >] {
130                #[inline(always)]
131                fn clone(&self) -> Self {
132                    Self {
133                        inner: self.inner.clone_const(),
134                    }
135                }
136            }
137
138            impl BuildHasher for [< FNV $variant _ $underlying_type HasherBuilder >] {
139                type Hasher = [< FNV $variant _ $underlying_type >];
140
141                #[inline(always)]
142                fn build_hasher(&self) -> Self::Hasher {
143                    self.create_hasher()
144                }
145            }
146        }
147    };
148}
149
150build_fnv!(1a, 64);
151build_fnv!(1, 64);
152build_fnv!(1a, 128);
153build_fnv!(1, 128);
154
155impl FNV1a_64 {
156    const INITIAL: u64 = 0xcbf29ce484222325;
157    const MULTIPLIER: u64 = 0x00000100000001b3;
158
159    /// Updates internal [`FNV1a_64`] state with a given bytes block.
160    pub const fn result_const(&mut self, data: &[u8]) {
161        let mut current = self.state;
162        let mut index = 0;
163        let len = data.len();
164        while index < len {
165            let byte = data[index];
166            current = current ^ (byte as u64);
167            current = current.wrapping_mul(Self::MULTIPLIER);
168            index += 1;
169        }
170        self.state = current;
171    }
172}
173
174impl FNV1_64 {
175    const INITIAL: u64 = 0xcbf29ce484222325;
176    const MULTIPLIER: u64 = 0x00000100000001b3;
177
178    /// Updates internal [`FNV1_64`] state with a given bytes block.
179    pub const fn result_const(&mut self, data: &[u8]) {
180        let mut current = self.state;
181        let mut index = 0;
182        let len = data.len();
183        while index < len {
184            let byte = data[index];
185            current = current.wrapping_mul(Self::MULTIPLIER);
186            current = current ^ (byte as u64);
187            index += 1;
188        }
189        self.state = current;
190    }
191}
192
193impl FNV1a_128 {
194    const INITIAL: u128 = 0x6c62272e07bb014262b821756295c58d;
195    const MULTIPLIER: u128 = 0x0000000001000000000000000000013b;
196
197    /// Updates internal [`FNV1a_128`] state with a given bytes block.
198    pub const fn result_const(&mut self, data: &[u8]) {
199        let mut current = self.state;
200        let mut index = 0;
201        let len = data.len();
202        while index < len {
203            let byte = data[index];
204            current = current ^ (byte as u128);
205            current = current.wrapping_mul(Self::MULTIPLIER);
206            index += 1;
207        }
208        self.state = current;
209    }
210}
211
212impl FNV1_128 {
213    const INITIAL: u128 = 0x6c62272e07bb014262b821756295c58d;
214    const MULTIPLIER: u128 = 0x0000000001000000000000000000013b;
215
216    /// Updates internal [`FNV1_128`] state with a given bytes block.
217    pub const fn result_const(&mut self, data: &[u8]) {
218        let mut current = self.state;
219        let mut index = 0;
220        let len = data.len();
221        while index < len {
222            let byte = data[index];
223            current = current.wrapping_mul(Self::MULTIPLIER);
224            current = current ^ (byte as u128);
225            index += 1;
226        }
227        self.state = current;
228    }
229}