]>
Commit | Line | Data |
---|---|---|
7cac9316 XL |
1 | //! Simple CRC bindings backed by miniz.c |
2 | ||
7cac9316 | 3 | use std::io; |
60c5eb7d | 4 | use std::io::prelude::*; |
7cac9316 | 5 | |
0731742a | 6 | use crc32fast::Hasher; |
7cac9316 | 7 | |
ea8adc8c XL |
8 | /// The CRC calculated by a [`CrcReader`]. |
9 | /// | |
10 | /// [`CrcReader`]: struct.CrcReader.html | |
11 | #[derive(Debug)] | |
7cac9316 | 12 | pub struct Crc { |
7cac9316 | 13 | amt: u32, |
0731742a | 14 | hasher: Hasher, |
7cac9316 XL |
15 | } |
16 | ||
ea8adc8c XL |
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)] | |
7cac9316 XL |
21 | pub struct CrcReader<R> { |
22 | inner: R, | |
23 | crc: Crc, | |
24 | } | |
25 | ||
26 | impl Crc { | |
27 | /// Create a new CRC. | |
28 | pub fn new() -> Crc { | |
60c5eb7d XL |
29 | Crc { |
30 | amt: 0, | |
31 | hasher: Hasher::new(), | |
32 | } | |
7cac9316 XL |
33 | } |
34 | ||
0731742a | 35 | /// Returns the current crc32 checksum. |
7cac9316 | 36 | pub fn sum(&self) -> u32 { |
0731742a | 37 | self.hasher.clone().finalize() |
7cac9316 XL |
38 | } |
39 | ||
40 | /// The number of bytes that have been used to calculate the CRC. | |
ff7c6d11 | 41 | /// This value is only accurate if the amount is lower than 2<sup>32</sup>. |
7cac9316 XL |
42 | pub fn amount(&self) -> u32 { |
43 | self.amt | |
44 | } | |
45 | ||
46 | /// Update the CRC with the bytes in `data`. | |
47 | pub fn update(&mut self, data: &[u8]) { | |
48 | self.amt = self.amt.wrapping_add(data.len() as u32); | |
0731742a | 49 | self.hasher.update(data); |
7cac9316 XL |
50 | } |
51 | ||
52 | /// Reset the CRC. | |
53 | pub fn reset(&mut self) { | |
7cac9316 | 54 | self.amt = 0; |
0731742a | 55 | self.hasher.reset(); |
7cac9316 XL |
56 | } |
57 | ||
58 | /// Combine the CRC with the CRC for the subsequent block of bytes. | |
59 | pub fn combine(&mut self, additional_crc: &Crc) { | |
7cac9316 | 60 | self.amt += additional_crc.amt; |
0731742a | 61 | self.hasher.combine(&additional_crc.hasher); |
7cac9316 XL |
62 | } |
63 | } | |
64 | ||
65 | impl<R: Read> CrcReader<R> { | |
66 | /// Create a new CrcReader. | |
67 | pub fn new(r: R) -> CrcReader<R> { | |
68 | CrcReader { | |
69 | inner: r, | |
70 | crc: Crc::new(), | |
71 | } | |
72 | } | |
ea8adc8c | 73 | } |
7cac9316 | 74 | |
ea8adc8c | 75 | impl<R> CrcReader<R> { |
7cac9316 XL |
76 | /// Get the Crc for this CrcReader. |
77 | pub fn crc(&self) -> &Crc { | |
78 | &self.crc | |
79 | } | |
80 | ||
81 | /// Get the reader that is wrapped by this CrcReader. | |
82 | pub fn into_inner(self) -> R { | |
83 | self.inner | |
84 | } | |
85 | ||
86 | /// Get the reader that is wrapped by this CrcReader by reference. | |
87 | pub fn get_ref(&self) -> &R { | |
88 | &self.inner | |
89 | } | |
90 | ||
91 | /// Get a mutable reference to the reader that is wrapped by this CrcReader. | |
92 | pub fn get_mut(&mut self) -> &mut R { | |
93 | &mut self.inner | |
94 | } | |
95 | ||
96 | /// Reset the Crc in this CrcReader. | |
97 | pub fn reset(&mut self) { | |
98 | self.crc.reset(); | |
99 | } | |
100 | } | |
101 | ||
102 | impl<R: Read> Read for CrcReader<R> { | |
103 | fn read(&mut self, into: &mut [u8]) -> io::Result<usize> { | |
b7449926 | 104 | let amt = self.inner.read(into)?; |
7cac9316 XL |
105 | self.crc.update(&into[..amt]); |
106 | Ok(amt) | |
107 | } | |
108 | } | |
109 | ||
110 | impl<R: BufRead> BufRead for CrcReader<R> { | |
111 | fn fill_buf(&mut self) -> io::Result<&[u8]> { | |
112 | self.inner.fill_buf() | |
113 | } | |
114 | fn consume(&mut self, amt: usize) { | |
115 | if let Ok(data) = self.inner.fill_buf() { | |
116 | self.crc.update(&data[..amt]); | |
117 | } | |
118 | self.inner.consume(amt); | |
119 | } | |
120 | } | |
b7449926 XL |
121 | |
122 | /// A wrapper around a [`Write`] that calculates the CRC. | |
123 | /// | |
124 | /// [`Write`]: https://doc.rust-lang.org/std/io/trait.Write.html | |
125 | #[derive(Debug)] | |
126 | pub struct CrcWriter<W> { | |
127 | inner: W, | |
128 | crc: Crc, | |
129 | } | |
130 | ||
131 | impl<W> CrcWriter<W> { | |
132 | /// Get the Crc for this CrcWriter. | |
133 | pub fn crc(&self) -> &Crc { | |
134 | &self.crc | |
135 | } | |
136 | ||
137 | /// Get the writer that is wrapped by this CrcWriter. | |
138 | pub fn into_inner(self) -> W { | |
139 | self.inner | |
140 | } | |
141 | ||
142 | /// Get the writer that is wrapped by this CrcWriter by reference. | |
143 | pub fn get_ref(&self) -> &W { | |
144 | &self.inner | |
145 | } | |
146 | ||
147 | /// Get a mutable reference to the writer that is wrapped by this CrcWriter. | |
148 | pub fn get_mut(&mut self) -> &mut W { | |
149 | &mut self.inner | |
150 | } | |
151 | ||
152 | /// Reset the Crc in this CrcWriter. | |
153 | pub fn reset(&mut self) { | |
154 | self.crc.reset(); | |
155 | } | |
156 | } | |
157 | ||
158 | impl<W: Write> CrcWriter<W> { | |
159 | /// Create a new CrcWriter. | |
160 | pub fn new(w: W) -> CrcWriter<W> { | |
161 | CrcWriter { | |
162 | inner: w, | |
163 | crc: Crc::new(), | |
164 | } | |
165 | } | |
166 | } | |
167 | ||
168 | impl<W: Write> Write for CrcWriter<W> { | |
169 | fn write(&mut self, buf: &[u8]) -> io::Result<usize> { | |
60c5eb7d | 170 | let amt = self.inner.write(buf)?; |
b7449926 XL |
171 | self.crc.update(&buf[..amt]); |
172 | Ok(amt) | |
173 | } | |
174 | ||
175 | fn flush(&mut self) -> io::Result<()> { | |
176 | self.inner.flush() | |
177 | } | |
178 | } |