Coverage Report

Created: 2026-02-14 07:04

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/flate2-1.1.9/src/crc.rs
Line
Count
Source
1
//! Simple CRC bindings backed by miniz.c
2
3
use std::io;
4
use std::io::prelude::*;
5
6
#[cfg(not(feature = "zlib-rs"))]
7
pub use impl_crc32fast::Crc;
8
9
#[cfg(feature = "zlib-rs")]
10
pub use impl_zlib_rs::Crc;
11
12
#[cfg(not(feature = "zlib-rs"))]
13
mod impl_crc32fast {
14
    use crc32fast::Hasher;
15
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,
23
    }
24
25
    impl Crc {
26
        /// Create a new CRC.
27
0
        pub fn new() -> Self {
28
0
            Self::default()
29
0
        }
30
31
        /// Returns the current crc32 checksum.
32
0
        pub fn sum(&self) -> u32 {
33
0
            self.hasher.clone().finalize()
34
0
        }
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
0
        pub fn amount(&self) -> u32 {
39
0
            self.amt
40
0
        }
41
42
        /// Update the CRC with the bytes in `data`.
43
0
        pub fn update(&mut self, data: &[u8]) {
44
0
            self.amt = self.amt.wrapping_add(data.len() as u32);
45
0
            self.hasher.update(data);
46
0
        }
47
48
        /// Reset the CRC.
49
0
        pub fn reset(&mut self) {
50
0
            self.amt = 0;
51
0
            self.hasher.reset();
52
0
        }
53
54
        /// Combine the CRC with the CRC for the subsequent block of bytes.
55
0
        pub fn combine(&mut self, additional_crc: &Self) {
56
0
            self.amt = self.amt.wrapping_add(additional_crc.amt);
57
0
            self.hasher.combine(&additional_crc.hasher);
58
0
        }
59
    }
60
}
61
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,
71
    }
72
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
        }
111
    }
112
}
113
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
123
impl<R: Read> CrcReader<R> {
124
    /// Create a new `CrcReader`.
125
0
    pub fn new(r: R) -> CrcReader<R> {
126
0
        CrcReader {
127
0
            inner: r,
128
0
            crc: Crc::new(),
129
0
        }
130
0
    }
131
}
132
133
impl<R> CrcReader<R> {
134
    /// Get the Crc for this `CrcReader`.
135
0
    pub fn crc(&self) -> &Crc {
136
0
        &self.crc
137
0
    }
138
139
    /// Get the reader that is wrapped by this `CrcReader`.
140
0
    pub fn into_inner(self) -> R {
141
0
        self.inner
142
0
    }
143
144
    /// Get the reader that is wrapped by this `CrcReader` by reference.
145
0
    pub fn get_ref(&self) -> &R {
146
0
        &self.inner
147
0
    }
148
149
    /// Get a mutable reference to the reader that is wrapped by this `CrcReader`.
150
0
    pub fn get_mut(&mut self) -> &mut R {
151
0
        &mut self.inner
152
0
    }
153
154
    /// Reset the Crc in this `CrcReader`.
155
0
    pub fn reset(&mut self) {
156
0
        self.crc.reset();
157
0
    }
158
}
159
160
impl<R: Read> Read for CrcReader<R> {
161
0
    fn read(&mut self, into: &mut [u8]) -> io::Result<usize> {
162
0
        let amt = self.inner.read(into)?;
163
0
        self.crc.update(&into[..amt]);
164
0
        Ok(amt)
165
0
    }
166
}
167
168
impl<R: BufRead> BufRead for CrcReader<R> {
169
0
    fn fill_buf(&mut self) -> io::Result<&[u8]> {
170
0
        self.inner.fill_buf()
171
0
    }
172
0
    fn consume(&mut self, amt: usize) {
173
0
        if let Ok(data) = self.inner.fill_buf() {
174
0
            self.crc.update(&data[..amt]);
175
0
        }
176
0
        self.inner.consume(amt);
177
0
    }
178
}
179
180
/// A wrapper around a [`Write`] that calculates the CRC.
181
///
182
/// [`Write`]: https://doc.rust-lang.org/std/io/trait.Write.html
183
#[derive(Debug)]
184
pub struct CrcWriter<W> {
185
    inner: W,
186
    crc: Crc,
187
}
188
189
impl<W> CrcWriter<W> {
190
    /// Get the Crc for this `CrcWriter`.
191
0
    pub fn crc(&self) -> &Crc {
192
0
        &self.crc
193
0
    }
194
195
    /// Get the writer that is wrapped by this `CrcWriter`.
196
0
    pub fn into_inner(self) -> W {
197
0
        self.inner
198
0
    }
199
200
    /// Get the writer that is wrapped by this `CrcWriter` by reference.
201
0
    pub fn get_ref(&self) -> &W {
202
0
        &self.inner
203
0
    }
204
205
    /// Get a mutable reference to the writer that is wrapped by this `CrcWriter`.
206
0
    pub fn get_mut(&mut self) -> &mut W {
207
0
        &mut self.inner
208
0
    }
209
210
    /// Reset the Crc in this `CrcWriter`.
211
0
    pub fn reset(&mut self) {
212
0
        self.crc.reset();
213
0
    }
214
}
215
216
impl<W: Write> CrcWriter<W> {
217
    /// Create a new `CrcWriter`.
218
0
    pub fn new(w: W) -> CrcWriter<W> {
219
0
        CrcWriter {
220
0
            inner: w,
221
0
            crc: Crc::new(),
222
0
        }
223
0
    }
224
}
225
226
impl<W: Write> Write for CrcWriter<W> {
227
0
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
228
0
        let amt = self.inner.write(buf)?;
229
0
        self.crc.update(&buf[..amt]);
230
0
        Ok(amt)
231
0
    }
232
233
0
    fn flush(&mut self) -> io::Result<()> {
234
0
        self.inner.flush()
235
0
    }
236
}
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
}