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