Coverage Report

Created: 2026-08-31 06:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}