Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit c584e97

Browse files
committed
use zlib-rs for crc32 (when available)
1 parent 8b66c27 commit c584e97

1 file changed

Lines changed: 177 additions & 42 deletions

File tree

src/crc.rs

Lines changed: 177 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -3,62 +3,123 @@
33
use std::io;
44
use std::io::prelude::*;
55

6-
use crc32fast::Hasher;
6+
#[cfg(not(feature = "zlib-rs"))]
7+
pub use impl_crc32fast::Crc;
78

8-
/// The CRC calculated by a [`CrcReader`].
9-
///
10-
/// [`CrcReader`]: struct.CrcReader.html
11-
#[derive(Debug, Default)]
12-
pub struct Crc {
13-
amt: u32,
14-
hasher: Hasher,
15-
}
9+
#[cfg(feature = "zlib-rs")]
10+
pub use impl_zlib_rs::Crc;
1611

17-
/// A wrapper around a [`Read`] that calculates the CRC.
18-
///
19-
/// [`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html
20-
#[derive(Debug)]
21-
pub struct CrcReader<R> {
22-
inner: R,
23-
crc: Crc,
24-
}
12+
#[cfg(not(feature = "zlib-rs"))]
13+
mod impl_crc32fast {
14+
use crc32fast::Hasher;
2515

26-
impl Crc {
27-
/// Create a new CRC.
28-
pub fn new() -> Self {
29-
Self::default()
16+
/// The CRC calculated by a [`CrcReader`].
17+
///
18+
/// [`CrcReader`]: struct.CrcReader.html
19+
#[derive(Debug, Default)]
20+
pub struct Crc {
21+
amt: u32,
22+
hasher: Hasher,
3023
}
3124

32-
/// Returns the current crc32 checksum.
33-
pub fn sum(&self) -> u32 {
34-
self.hasher.clone().finalize()
35-
}
25+
impl Crc {
26+
/// Create a new CRC.
27+
pub fn new() -> Self {
28+
Self::default()
29+
}
3630

37-
/// The number of bytes that have been used to calculate the CRC.
38-
/// This value is only accurate if the amount is lower than 2<sup>32</sup>.
39-
pub fn amount(&self) -> u32 {
40-
self.amt
41-
}
31+
/// Returns the current crc32 checksum.
32+
pub fn sum(&self) -> u32 {
33+
self.hasher.clone().finalize()
34+
}
35+
36+
/// The number of bytes that have been used to calculate the CRC.
37+
/// This value is only accurate if the amount is lower than 2<sup>32</sup>.
38+
pub fn amount(&self) -> u32 {
39+
self.amt
40+
}
41+
42+
/// Update the CRC with the bytes in `data`.
43+
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+
/// Reset the CRC.
49+
pub fn reset(&mut self) {
50+
self.amt = 0;
51+
self.hasher.reset();
52+
}
4253

43-
/// Update the CRC with the bytes in `data`.
44-
pub fn update(&mut self, data: &[u8]) {
45-
self.amt = self.amt.wrapping_add(data.len() as u32);
46-
self.hasher.update(data);
54+
/// Combine the CRC with the CRC for the subsequent block of bytes.
55+
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+
}
4759
}
60+
}
4861

49-
/// Reset the CRC.
50-
pub fn reset(&mut self) {
51-
self.amt = 0;
52-
self.hasher.reset();
62+
#[cfg(feature = "zlib-rs")]
63+
mod impl_zlib_rs {
64+
/// The CRC calculated by a [`CrcReader`].
65+
///
66+
/// [`CrcReader`]: struct.CrcReader.html
67+
#[derive(Debug, Default)]
68+
pub struct Crc {
69+
consumed: u64,
70+
state: u32,
5371
}
5472

55-
/// Combine the CRC with the CRC for the subsequent block of bytes.
56-
pub fn combine(&mut self, additional_crc: &Crc) {
57-
self.amt = self.amt.wrapping_add(additional_crc.amt);
58-
self.hasher.combine(&additional_crc.hasher);
73+
impl Crc {
74+
/// Create a new CRC.
75+
pub fn new() -> Self {
76+
Self::default()
77+
}
78+
79+
/// Returns the current crc32 checksum.
80+
pub fn sum(&self) -> u32 {
81+
self.state
82+
}
83+
84+
/// The number of bytes that have been used to calculate the CRC.
85+
/// This value is only accurate if the amount is lower than 2<sup>32</sup>.
86+
pub fn amount(&self) -> u32 {
87+
self.consumed as u32
88+
}
89+
90+
/// Update the CRC with the bytes in `data`.
91+
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+
/// Reset the CRC.
97+
pub fn reset(&mut self) {
98+
self.consumed = 0;
99+
self.state = 0
100+
}
101+
102+
/// Combine the CRC with the CRC for the subsequent block of bytes.
103+
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+
}
59111
}
60112
}
61113

114+
/// A wrapper around a [`Read`] that calculates the CRC.
115+
///
116+
/// [`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html
117+
#[derive(Debug)]
118+
pub struct CrcReader<R> {
119+
inner: R,
120+
crc: Crc,
121+
}
122+
62123
impl<R: Read> CrcReader<R> {
63124
/// Create a new `CrcReader`.
64125
pub fn new(r: R) -> CrcReader<R> {
@@ -173,3 +234,77 @@ impl<W: Write> Write for CrcWriter<W> {
173234
self.inner.flush()
174235
}
175236
}
237+
238+
#[cfg(test)]
239+
mod 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+
}

0 commit comments

Comments
 (0)