1#![cfg_attr(not(feature = "std"), no_std)]
43#![deny(missing_docs)]
44#![deny(unsafe_code)]
45use core::fmt;
46use core::hash;
47
48mod baseline;
49mod combine;
50mod specialized;
51mod table;
52
53#[inline]
57pub fn hash(buf: &[u8]) -> u32 {
58 let mut h = Hasher::new();
59 h.update(buf);
60 h.finalize()
61}
62
63#[derive(Clone)]
64pub struct Hasher {
66 amount: u64,
67 state: u32,
68 spec: Option<specialized::State>,
69}
70
71const DEFAULT_INIT_STATE: u32 = 0;
72
73impl Hasher {
74 #[inline]
79 pub fn new() -> Self {
80 Self::new_with_initial(DEFAULT_INIT_STATE)
81 }
82
83 #[inline]
88 pub fn new_with_initial(init: u32) -> Self {
89 Self::new_with_initial_len(init, 0)
90 }
91
92 #[inline]
98 pub fn new_with_initial_len(init: u32, amount: u64) -> Self {
99 Self::internal_new_specialized(init, amount)
100 .unwrap_or_else(|| Self::internal_new_baseline(init, amount))
101 }
102
103 #[doc(hidden)]
104 #[inline]
106 pub fn internal_new_baseline(init: u32, amount: u64) -> Self {
107 Hasher {
108 amount,
109 state: init,
110 spec: None,
111 }
112 }
113
114 #[doc(hidden)]
115 #[inline]
117 pub fn internal_new_specialized(init: u32, amount: u64) -> Option<Self> {
118 Some(Hasher {
119 amount,
120 state: init,
121 spec: Some(specialized::State::new()?),
122 })
123 }
124
125 #[inline]
127 pub fn update(&mut self, buf: &[u8]) {
128 self.amount += buf.len() as u64;
129 self.state = match &self.spec {
130 None => baseline::update_fast_16(self.state, buf),
131 Some(spec) => spec.update(self.state, buf),
132 };
133 }
134
135 #[inline]
153 pub fn total_len(&self) -> u64 {
154 self.amount
155 }
156
157 #[inline]
159 pub fn finalize(self) -> u32 {
160 self.state
161 }
162
163 #[inline]
165 pub fn reset(&mut self) {
166 self.state = 0;
167 self.amount = 0;
168 }
169
170 pub fn combine(&mut self, other: &Self) {
172 self.amount += other.amount;
173 self.state = combine::combine(self.state, other.state, other.amount);
174 }
175}
176
177impl fmt::Debug for Hasher {
178 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
179 f.debug_struct("crc32fast::Hasher").finish()
180 }
181}
182
183impl Default for Hasher {
184 fn default() -> Self {
185 Self::new()
186 }
187}
188
189impl hash::Hasher for Hasher {
190 fn write(&mut self, bytes: &[u8]) {
191 self.update(bytes)
192 }
193
194 fn finish(&self) -> u64 {
195 u64::from(self.clone().finalize())
196 }
197}
198
199#[cfg(test)]
200mod test {
201 use super::Hasher;
202
203 #[test]
204 fn total_len_tracks_resumed_and_combined_blocks() {
205 let prefix = b"hello";
206 let suffix = b" world";
207 let mut hasher = Hasher::new_with_initial_len(super::hash(prefix), prefix.len() as u64);
208 assert_eq!(hasher.total_len(), 5);
209 hasher.update(b" ");
210 assert_eq!(hasher.total_len(), 6);
211
212 let mut remaining = Hasher::new();
213 remaining.update(&suffix[1..]);
214 hasher.combine(&remaining);
215 assert_eq!(hasher.total_len(), 11);
216 assert_eq!(hasher.clone().finalize(), super::hash(b"hello world"));
217 assert_eq!(remaining.total_len(), 5);
218
219 hasher.reset();
220 assert_eq!(hasher.total_len(), 0);
221 hasher.update(b"again");
222 assert_eq!(hasher.total_len(), 5);
223 assert_eq!(hasher.finalize(), super::hash(b"again"));
224 }
225
226 #[test]
227 fn total_len_for_empty_and_unknown_initial_length() {
228 let mut hasher = Hasher::new();
229 assert_eq!(hasher.total_len(), 0);
230 hasher.update(b"");
231 hasher.combine(&Hasher::new());
232 assert_eq!(hasher.total_len(), 0);
233 assert_eq!(
234 Hasher::new_with_initial(super::hash(b"prefix")).total_len(),
235 0
236 );
237 assert_eq!(
238 Hasher::new_with_initial_len(0, u64::MAX).total_len(),
239 u64::MAX
240 );
241 }
242
243 quickcheck::quickcheck! {
244 fn combine(bytes_1: Vec<u8>, bytes_2: Vec<u8>) -> bool {
245 let mut hash_a = Hasher::new();
246 hash_a.update(&bytes_1);
247 hash_a.update(&bytes_2);
248 let mut hash_b = Hasher::new();
249 hash_b.update(&bytes_2);
250 let mut hash_c = Hasher::new();
251 hash_c.update(&bytes_1);
252 hash_c.combine(&hash_b);
253
254 hash_a.finalize() == hash_c.finalize()
255 }
256
257 fn combine_from_len(bytes_1: Vec<u8>, bytes_2: Vec<u8>) -> bool {
258 let mut hash_a = Hasher::new();
259 hash_a.update(&bytes_1);
260
261 let mut hash_b = Hasher::new();
262 hash_b.update(&bytes_2);
263
264 let mut hash_ab = Hasher::new();
265 hash_ab.update(&bytes_1);
266 hash_ab.update(&bytes_2);
267 let ab = hash_ab.finalize();
268
269 hash_a.combine(&hash_b);
270 hash_a.finalize() == ab
271 }
272 }
273}