/rust/registry/src/index.crates.io-1949cf8c6b5b557f/flate2-1.1.10/src/crc.rs
Line | Count | Source |
1 | | //! Simple CRC bindings backed by miniz.c |
2 | | |
3 | | use crate::io; |
4 | | use crate::io::{BufRead, Read, Write}; |
5 | | |
6 | | /// The CRC calculated by a [`CrcReader`]. |
7 | | #[derive(Debug, Default)] |
8 | | pub struct Crc { |
9 | | inner: inner::Crc, |
10 | | } |
11 | | |
12 | | impl Crc { |
13 | | /// Create a new CRC. |
14 | 0 | pub fn new() -> Self { |
15 | 0 | Self::default() |
16 | 0 | } |
17 | | |
18 | | /// Returns the current crc32 checksum. |
19 | 0 | pub fn sum(&self) -> u32 { |
20 | 0 | self.inner.sum() |
21 | 0 | } |
22 | | |
23 | | /// The number of bytes that have been used to calculate the CRC. |
24 | | /// This value is only accurate if the amount is lower than 2<sup>32</sup>. |
25 | 0 | pub fn amount(&self) -> u32 { |
26 | 0 | self.inner.amount() |
27 | 0 | } |
28 | | |
29 | | /// Update the CRC with the bytes in `data`. |
30 | 0 | pub fn update(&mut self, data: &[u8]) { |
31 | 0 | self.inner.update(data); |
32 | 0 | } |
33 | | |
34 | | /// Reset the CRC, to start a new hash. |
35 | | /// |
36 | | /// Do this in favor of creating a new `Crc` instance. |
37 | 0 | pub fn reset(&mut self) { |
38 | 0 | self.inner.reset(); |
39 | 0 | } |
40 | | |
41 | | /// Combine the CRC with the CRC for the subsequent block of bytes. |
42 | 0 | pub fn combine(&mut self, additional_crc: &Self) { |
43 | 0 | self.inner.combine(&additional_crc.inner); |
44 | 0 | } |
45 | | } |
46 | | |
47 | | #[cfg(not(feature = "zlib-rs"))] |
48 | | mod 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 | 0 | pub fn sum(&self) -> u32 { |
60 | 0 | self.hasher.clone().finalize() |
61 | 0 | } |
62 | | |
63 | | #[inline] |
64 | 0 | pub fn amount(&self) -> u32 { |
65 | 0 | self.amt |
66 | 0 | } |
67 | | |
68 | | #[inline] |
69 | 0 | pub fn update(&mut self, data: &[u8]) { |
70 | 0 | self.amt = self.amt.wrapping_add(data.len() as u32); |
71 | 0 | self.hasher.update(data); |
72 | 0 | } |
73 | | |
74 | | #[inline] |
75 | 0 | pub fn reset(&mut self) { |
76 | 0 | self.amt = 0; |
77 | 0 | self.hasher.reset(); |
78 | 0 | } |
79 | | |
80 | | #[inline] |
81 | 0 | pub fn combine(&mut self, additional_crc: &Self) { |
82 | 0 | self.amt = self.amt.wrapping_add(additional_crc.amt); |
83 | 0 | self.hasher.combine(&additional_crc.hasher); |
84 | 0 | } |
85 | | } |
86 | | } |
87 | | |
88 | | #[cfg(feature = "zlib-rs")] |
89 | | mod 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 | | /// A wrapper around a [`Read`] that calculates the CRC. |
132 | | /// |
133 | | /// [`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html |
134 | | #[derive(Debug)] |
135 | | pub struct CrcReader<R> { |
136 | | inner: R, |
137 | | crc: Crc, |
138 | | } |
139 | | |
140 | | impl<R: Read> CrcReader<R> { |
141 | | /// Create a new `CrcReader`. |
142 | 0 | pub fn new(r: R) -> CrcReader<R> { |
143 | 0 | CrcReader { |
144 | 0 | inner: r, |
145 | 0 | crc: Crc::new(), |
146 | 0 | } |
147 | 0 | } |
148 | | } |
149 | | |
150 | | impl<R> CrcReader<R> { |
151 | | /// Get the Crc for this `CrcReader`. |
152 | 0 | pub fn crc(&self) -> &Crc { |
153 | 0 | &self.crc |
154 | 0 | } |
155 | | |
156 | | /// Get the reader that is wrapped by this `CrcReader`. |
157 | 0 | pub fn into_inner(self) -> R { |
158 | 0 | self.inner |
159 | 0 | } |
160 | | |
161 | | /// Get the reader that is wrapped by this `CrcReader` by reference. |
162 | 0 | pub fn get_ref(&self) -> &R { |
163 | 0 | &self.inner |
164 | 0 | } |
165 | | |
166 | | /// Get a mutable reference to the reader that is wrapped by this `CrcReader`. |
167 | 0 | pub fn get_mut(&mut self) -> &mut R { |
168 | 0 | &mut self.inner |
169 | 0 | } |
170 | | |
171 | | /// Reset the Crc in this `CrcReader`. |
172 | 0 | pub fn reset(&mut self) { |
173 | 0 | self.crc.reset(); |
174 | 0 | } |
175 | | } |
176 | | |
177 | | impl<R: Read> Read for CrcReader<R> { |
178 | 0 | fn read(&mut self, into: &mut [u8]) -> io::Result<usize> { |
179 | 0 | let amt = self.inner.read(into)?; |
180 | 0 | self.crc.update(&into[..amt]); |
181 | 0 | Ok(amt) |
182 | 0 | } |
183 | | } |
184 | | |
185 | | impl<R: BufRead> BufRead for CrcReader<R> { |
186 | 0 | fn fill_buf(&mut self) -> io::Result<&[u8]> { |
187 | 0 | self.inner.fill_buf() |
188 | 0 | } |
189 | 0 | fn consume(&mut self, amt: usize) { |
190 | 0 | if let Ok(data) = self.inner.fill_buf() { |
191 | 0 | self.crc.update(&data[..amt]); |
192 | 0 | } |
193 | 0 | self.inner.consume(amt); |
194 | 0 | } |
195 | | } |
196 | | |
197 | | /// A wrapper around a [`Write`] that calculates the CRC. |
198 | | /// |
199 | | /// [`Write`]: https://doc.rust-lang.org/std/io/trait.Write.html |
200 | | #[derive(Debug)] |
201 | | pub struct CrcWriter<W> { |
202 | | inner: W, |
203 | | crc: Crc, |
204 | | } |
205 | | |
206 | | impl<W> CrcWriter<W> { |
207 | | /// Get the Crc for this `CrcWriter`. |
208 | 0 | pub fn crc(&self) -> &Crc { |
209 | 0 | &self.crc |
210 | 0 | } |
211 | | |
212 | | /// Get the writer that is wrapped by this `CrcWriter`. |
213 | 0 | pub fn into_inner(self) -> W { |
214 | 0 | self.inner |
215 | 0 | } |
216 | | |
217 | | /// Get the writer that is wrapped by this `CrcWriter` by reference. |
218 | 0 | pub fn get_ref(&self) -> &W { |
219 | 0 | &self.inner |
220 | 0 | } |
221 | | |
222 | | /// Get a mutable reference to the writer that is wrapped by this `CrcWriter`. |
223 | 0 | pub fn get_mut(&mut self) -> &mut W { |
224 | 0 | &mut self.inner |
225 | 0 | } |
226 | | |
227 | | /// Reset the Crc in this `CrcWriter`. |
228 | 0 | pub fn reset(&mut self) { |
229 | 0 | self.crc.reset(); |
230 | 0 | } |
231 | | } |
232 | | |
233 | | impl<W: Write> CrcWriter<W> { |
234 | | /// Create a new `CrcWriter`. |
235 | 0 | pub fn new(w: W) -> CrcWriter<W> { |
236 | 0 | CrcWriter { |
237 | 0 | inner: w, |
238 | 0 | crc: Crc::new(), |
239 | 0 | } |
240 | 0 | } |
241 | | } |
242 | | |
243 | | impl<W: Write> Write for CrcWriter<W> { |
244 | 0 | fn write(&mut self, buf: &[u8]) -> io::Result<usize> { |
245 | 0 | let amt = self.inner.write(buf)?; |
246 | 0 | self.crc.update(&buf[..amt]); |
247 | 0 | Ok(amt) |
248 | 0 | } |
249 | | |
250 | 0 | fn flush(&mut self) -> io::Result<()> { |
251 | 0 | self.inner.flush() |
252 | 0 | } |
253 | | } |
254 | | |
255 | | #[cfg(test)] |
256 | | mod 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 | | assert_eq!(ca.amount(), 11); |
323 | | assert_eq!(ca.sum(), sum_of(b"hello world")); |
324 | | } |
325 | | } |