codek/
with_checksum.rs

1use std::io::Error;
2use std::io::Read;
3use std::io::Write;
4
5use crate::checksum_reader::ChecksumReader;
6use crate::checksum_writer::ChecksumWriter;
7use crate::codec::Codec;
8use crate::fixed_size::FixedSize;
9
10/// A encoding helper that appends a checksum to the end of the encoded data.
11#[derive(Debug)]
12#[derive(Clone)]
13#[derive(PartialEq, Eq)]
14pub struct WithChecksum<T> {
15    pub(crate) data: T,
16}
17
18impl<T> WithChecksum<T> {
19    pub fn new(data: T) -> Self {
20        Self { data }
21    }
22
23    pub fn into_inner(self) -> T {
24        self.data
25    }
26}
27
28impl<T: FixedSize> FixedSize for WithChecksum<T> {
29    fn encoded_size() -> usize {
30        T::encoded_size() + 8
31    }
32}
33
34impl<T> Codec for WithChecksum<T>
35where T: Codec
36{
37    fn encode<W: Write>(&self, mut w: W) -> Result<usize, Error> {
38        let mut n = 0;
39        let mut cw = ChecksumWriter::new(&mut w);
40
41        n += self.data.encode(&mut cw)?;
42        n += cw.write_checksum()?;
43
44        Ok(n)
45    }
46
47    fn decode<R: Read>(r: R) -> Result<Self, Error> {
48        let mut cr = ChecksumReader::new(r);
49
50        let data = T::decode(&mut cr)?;
51        cr.verify_checksum(|| "WithChecksum::decode()")?;
52
53        let meta = Self { data };
54
55        Ok(meta)
56    }
57}
58
59#[cfg(test)]
60mod tests {
61    use crate::codec::Codec;
62    use crate::testing::test_codec;
63    use crate::with_checksum::WithChecksum;
64
65    #[test]
66    fn test_with_checksum_codec() -> anyhow::Result<()> {
67        let wc = WithChecksum::<u64>::new(5);
68        let mut b = Vec::new();
69        let n = wc.encode(&mut b)?;
70        assert_eq!(n, b.len());
71
72        assert_eq!(
73            vec![
74                0, 0, 0, 0, 0, 0, 0, 5, // data
75                0, 0, 0, 0, 21, 72, 43, 230, // checksum
76            ],
77            b
78        );
79
80        test_codec(b.as_slice(), &wc)?;
81
82        Ok(())
83    }
84}