1#![cfg_attr(not(feature = "std"), no_std)]
38#![deny(missing_docs)]
39use core::fmt;
40use core::hash;
41
42mod baseline;
43mod combine;
44mod specialized;
45mod table;
46
47pub fn hash(buf: &[u8]) -> u32 {
51 let mut h = Hasher::new();
52 h.update(buf);
53 h.finalize()
54}
55
56#[derive(Clone)]
57enum State {
58 Baseline(baseline::State),
59 Specialized(specialized::State),
60}
61
62#[derive(Clone)]
63pub struct Hasher {
65 amount: u64,
66 state: State,
67}
68
69const DEFAULT_INIT_STATE: u32 = 0;
70
71impl Hasher {
72 pub fn new() -> Self {
77 Self::new_with_initial(DEFAULT_INIT_STATE)
78 }
79
80 pub fn new_with_initial(init: u32) -> Self {
85 Self::new_with_initial_len(init, 0)
86 }
87
88 pub fn new_with_initial_len(init: u32, amount: u64) -> Self {
94 Self::internal_new_specialized(init, amount)
95 .unwrap_or_else(|| Self::internal_new_baseline(init, amount))
96 }
97
98 #[doc(hidden)]
99 pub fn internal_new_baseline(init: u32, amount: u64) -> Self {
101 Hasher {
102 amount,
103 state: State::Baseline(baseline::State::new(init)),
104 }
105 }
106
107 #[doc(hidden)]
108 pub fn internal_new_specialized(init: u32, amount: u64) -> Option<Self> {
110 {
111 if let Some(state) = specialized::State::new(init) {
112 return Some(Hasher {
113 amount,
114 state: State::Specialized(state),
115 });
116 }
117 }
118 None
119 }
120
121 pub fn update(&mut self, buf: &[u8]) {
123 self.amount += buf.len() as u64;
124 match self.state {
125 State::Baseline(ref mut state) => state.update(buf),
126 State::Specialized(ref mut state) => state.update(buf),
127 }
128 }
129
130 pub fn finalize(self) -> u32 {
132 match self.state {
133 State::Baseline(state) => state.finalize(),
134 State::Specialized(state) => state.finalize(),
135 }
136 }
137
138 pub fn reset(&mut self) {
140 self.amount = 0;
141 match self.state {
142 State::Baseline(ref mut state) => state.reset(),
143 State::Specialized(ref mut state) => state.reset(),
144 }
145 }
146
147 pub fn combine(&mut self, other: &Self) {
149 self.amount += other.amount;
150 let other_crc = other.clone().finalize();
151 match self.state {
152 State::Baseline(ref mut state) => state.combine(other_crc, other.amount),
153 State::Specialized(ref mut state) => state.combine(other_crc, other.amount),
154 }
155 }
156}
157
158impl fmt::Debug for Hasher {
159 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
160 f.debug_struct("crc32fast::Hasher").finish()
161 }
162}
163
164impl Default for Hasher {
165 fn default() -> Self {
166 Self::new()
167 }
168}
169
170impl hash::Hasher for Hasher {
171 fn write(&mut self, bytes: &[u8]) {
172 self.update(bytes)
173 }
174
175 fn finish(&self) -> u64 {
176 u64::from(self.clone().finalize())
177 }
178}
179
180#[cfg(test)]
181mod test {
182 use super::Hasher;
183
184 quickcheck::quickcheck! {
185 fn combine(bytes_1: Vec<u8>, bytes_2: Vec<u8>) -> bool {
186 let mut hash_a = Hasher::new();
187 hash_a.update(&bytes_1);
188 hash_a.update(&bytes_2);
189 let mut hash_b = Hasher::new();
190 hash_b.update(&bytes_2);
191 let mut hash_c = Hasher::new();
192 hash_c.update(&bytes_1);
193 hash_c.combine(&hash_b);
194
195 hash_a.finalize() == hash_c.finalize()
196 }
197
198 fn combine_from_len(bytes_1: Vec<u8>, bytes_2: Vec<u8>) -> bool {
199 let mut hash_a = Hasher::new();
200 hash_a.update(&bytes_1);
201
202 let mut hash_b = Hasher::new();
203 hash_b.update(&bytes_2);
204
205 let mut hash_ab = Hasher::new();
206 hash_ab.update(&bytes_1);
207 hash_ab.update(&bytes_2);
208 let ab = hash_ab.finalize();
209
210 hash_a.combine(&hash_b);
211 hash_a.finalize() == ab
212 }
213 }
214}