1use std::io;
4use std::io::prelude::*;
5
6#[cfg(not(feature = "zlib-rs"))]
7pub use impl_crc32fast::Crc;
8
9#[cfg(feature = "zlib-rs")]
10pub use impl_zlib_rs::Crc;
11
12#[cfg(not(feature = "zlib-rs"))]
13mod impl_crc32fast {
14 use crc32fast::Hasher;
15
16 #[derive(Debug, Default)]
20 pub struct Crc {
21 amt: u32,
22 hasher: Hasher,
23 }
24
25 impl Crc {
26 pub fn new() -> Self {
28 Self::default()
29 }
30
31 pub fn sum(&self) -> u32 {
33 self.hasher.clone().finalize()
34 }
35
36 pub fn amount(&self) -> u32 {
39 self.amt
40 }
41
42 pub fn update(&mut self, data: &[u8]) {
44 self.amt = self.amt.wrapping_add(data.len() as u32);
45 self.hasher.update(data);
46 }
47
48 pub fn reset(&mut self) {
50 self.amt = 0;
51 self.hasher.reset();
52 }
53
54 pub fn combine(&mut self, additional_crc: &Self) {
56 self.amt = self.amt.wrapping_add(additional_crc.amt);
57 self.hasher.combine(&additional_crc.hasher);
58 }
59 }
60}
61
62#[cfg(feature = "zlib-rs")]
63mod impl_zlib_rs {
64 #[derive(Debug, Default)]
68 pub struct Crc {
69 consumed: u64,
70 state: u32,
71 }
72
73 impl Crc {
74 pub fn new() -> Self {
76 Self::default()
77 }
78
79 pub fn sum(&self) -> u32 {
81 self.state
82 }
83
84 pub fn amount(&self) -> u32 {
87 self.consumed as u32
88 }
89
90 pub fn update(&mut self, data: &[u8]) {
92 self.consumed = self.consumed.wrapping_add(data.len() as u64);
93 self.state = zlib_rs::crc32::crc32(self.state, data);
94 }
95
96 pub fn reset(&mut self) {
98 self.consumed = 0;
99 self.state = 0
100 }
101
102 pub fn combine(&mut self, additional_crc: &Self) {
104 self.consumed = self.consumed.wrapping_add(additional_crc.consumed);
105 self.state = zlib_rs::crc32::crc32_combine(
106 self.state,
107 additional_crc.state,
108 additional_crc.consumed,
109 );
110 }
111 }
112}
113
114#[derive(Debug)]
118pub struct CrcReader<R> {
119 inner: R,
120 crc: Crc,
121}
122
123impl<R: Read> CrcReader<R> {
124 pub fn new(r: R) -> CrcReader<R> {
126 CrcReader {
127 inner: r,
128 crc: Crc::new(),
129 }
130 }
131}
132
133impl<R> CrcReader<R> {
134 pub fn crc(&self) -> &Crc {
136 &self.crc
137 }
138
139 pub fn into_inner(self) -> R {
141 self.inner
142 }
143
144 pub fn get_ref(&self) -> &R {
146 &self.inner
147 }
148
149 pub fn get_mut(&mut self) -> &mut R {
151 &mut self.inner
152 }
153
154 pub fn reset(&mut self) {
156 self.crc.reset();
157 }
158}
159
160impl<R: Read> Read for CrcReader<R> {
161 fn read(&mut self, into: &mut [u8]) -> io::Result<usize> {
162 let amt = self.inner.read(into)?;
163 self.crc.update(&into[..amt]);
164 Ok(amt)
165 }
166}
167
168impl<R: BufRead> BufRead for CrcReader<R> {
169 fn fill_buf(&mut self) -> io::Result<&[u8]> {
170 self.inner.fill_buf()
171 }
172 fn consume(&mut self, amt: usize) {
173 if let Ok(data) = self.inner.fill_buf() {
174 self.crc.update(&data[..amt]);
175 }
176 self.inner.consume(amt);
177 }
178}
179
180#[derive(Debug)]
184pub struct CrcWriter<W> {
185 inner: W,
186 crc: Crc,
187}
188
189impl<W> CrcWriter<W> {
190 pub fn crc(&self) -> &Crc {
192 &self.crc
193 }
194
195 pub fn into_inner(self) -> W {
197 self.inner
198 }
199
200 pub fn get_ref(&self) -> &W {
202 &self.inner
203 }
204
205 pub fn get_mut(&mut self) -> &mut W {
207 &mut self.inner
208 }
209
210 pub fn reset(&mut self) {
212 self.crc.reset();
213 }
214}
215
216impl<W: Write> CrcWriter<W> {
217 pub fn new(w: W) -> CrcWriter<W> {
219 CrcWriter {
220 inner: w,
221 crc: Crc::new(),
222 }
223 }
224}
225
226impl<W: Write> Write for CrcWriter<W> {
227 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
228 let amt = self.inner.write(buf)?;
229 self.crc.update(&buf[..amt]);
230 Ok(amt)
231 }
232
233 fn flush(&mut self) -> io::Result<()> {
234 self.inner.flush()
235 }
236}
237
238#[cfg(test)]
239mod tests {
240 use super::Crc;
241
242 fn crc_of(data: &[u8]) -> Crc {
243 let mut c = Crc::new();
244 c.update(data);
245 c
246 }
247
248 fn sum_of(data: &[u8]) -> u32 {
249 crc_of(data).sum()
250 }
251
252 #[test]
253 fn new_is_empty() {
254 let c = Crc::new();
255 assert_eq!(c.amount(), 0);
256 assert_eq!(c.sum(), 0);
257 }
258
259 #[test]
260 fn known_vector_hello() {
261 assert_eq!(sum_of(b"hello"), 0x3610_A686);
262 }
263
264 #[test]
265 fn known_vector_quick_brown_fox() {
266 assert_eq!(
267 sum_of(b"The quick brown fox jumps over the lazy dog"),
268 0x414F_A339
269 );
270 }
271
272 #[test]
273 fn update_is_streaming() {
274 let mut c = Crc::new();
275 c.update(b"hello");
276 c.update(b" ");
277 c.update(b"world");
278
279 assert_eq!(c.amount(), 11);
280 assert_eq!(c.sum(), sum_of(b"hello world"));
281 }
282
283 #[test]
284 fn reset_restores_initial_state() {
285 let mut c = Crc::new();
286 c.update(b"abc");
287 assert_ne!(c.sum(), 0);
288 assert_eq!(c.amount(), 3);
289
290 c.reset();
291 assert_eq!(c.amount(), 0);
292 assert_eq!(c.sum(), 0);
293 }
294
295 #[test]
296 fn combine_matches_concatenation() {
297 let a = b"hello ";
298 let b = b"world";
299
300 let mut ca = crc_of(a);
301 let cb = crc_of(b);
302
303 ca.combine(&cb);
304
305 dbg!(&ca);
306
307 assert_eq!(ca.amount(), 11);
308 assert_eq!(ca.sum(), sum_of(b"hello world"));
309 }
310}