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