1use std::io::{Read, Write};
3
4use crate::crc32c_append;
5
6pub struct Crc32cReader<R: Read> {
8 checksum: u32,
9 inner: R,
10}
11
12impl<R: Read> Crc32cReader<R> {
13 pub fn new(r: R) -> Self {
15 Self::new_with_seed(r, 0)
16 }
17
18 pub fn new_with_seed(r: R, seed: u32) -> Self {
20 Self {
21 checksum: seed,
22 inner: r,
23 }
24 }
25
26 pub fn into_inner(self) -> R {
28 self.inner
29 }
30
31 pub fn crc32c(&self) -> u32 {
33 self.checksum
34 }
35}
36
37impl<R: Read> Read for Crc32cReader<R> {
38 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
39 let out = self.inner.read(buf)?;
40 self.checksum = crc32c_append(self.checksum, &buf[..out]);
41 Ok(out)
42 }
43}
44
45pub struct Crc32cWriter<W: Write> {
47 checksum: u32,
48 inner: W,
49}
50
51impl<W: Write> Crc32cWriter<W> {
52 pub fn new(w: W) -> Self {
54 Self::new_with_seed(w, 0)
55 }
56
57 pub fn new_with_seed(w: W, seed: u32) -> Self {
59 Self {
60 checksum: seed,
61 inner: w,
62 }
63 }
64
65 pub fn into_inner(self) -> W {
67 self.inner
68 }
69
70 pub fn crc32c(&self) -> u32 {
72 self.checksum
73 }
74}
75
76impl<W: Write> Write for Crc32cWriter<W> {
77 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
78 let out = self.inner.write(buf)?;
79 self.checksum = crc32c_append(self.checksum, &buf[..out]);
80 Ok(out)
81 }
82
83 fn flush(&mut self) -> std::io::Result<()> {
84 self.inner.flush()
85 }
86}
87
88#[cfg(test)]
89mod tests {
90 use std::io::Cursor;
91
92 use super::*;
93
94 const TEST_STRING: &[u8] =
95 b"This is a very long string which is used to test the CRC-32-Castagnoli function.";
96 const CHECKSUM: u32 = 0x20_CB_1E_59;
97
98 #[test]
99 fn can_read() {
100 let mut reader = Crc32cReader::new(TEST_STRING);
101 let mut buf = Vec::default();
102 let n_read = reader.read_to_end(&mut buf).unwrap();
103 assert_eq!(n_read, TEST_STRING.len());
104 assert_eq!(buf.as_slice(), TEST_STRING);
105 assert_eq!(reader.crc32c(), CHECKSUM);
106 }
107
108 #[test]
109 fn can_write() {
110 let mut buf = Vec::<u8>::default();
111
112 let mut writer = Crc32cWriter::<Cursor<&mut Vec<u8>>>::new(Cursor::new(&mut buf));
113 writer.write_all(TEST_STRING).unwrap();
114 let checksum = writer.crc32c();
115
116 assert_eq!(buf.as_slice(), TEST_STRING);
117 assert_eq!(checksum, CHECKSUM);
118 }
119}