vmm/snapshot/
crc.rs

1// Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4//! Implements readers and writers that compute the CRC64 checksum of the bytes
5//! read/written.
6
7use std::io::Write;
8
9use crc64::crc64;
10
11/// Computes the CRC64 checksum of the written bytes.
12///
13/// ```
14/// use std::io::Write;
15///
16/// use vmm::snapshot::crc::CRC64Writer;
17///
18/// let mut buf = vec![0; 16];
19/// let write_buf = vec![123; 16];
20/// let mut slice = buf.as_mut_slice();
21///
22/// // Create a new writer from slice.
23/// let mut crc_writer = CRC64Writer::new(&mut slice);
24///
25/// crc_writer.write_all(&write_buf.as_slice()).unwrap();
26/// assert_eq!(crc_writer.checksum(), 0x29D5_3572_1632_6566);
27/// assert_eq!(write_buf, buf);
28/// ```
29#[derive(Debug)]
30pub struct CRC64Writer<T> {
31    /// The underlying raw writer. Using this directly will bypass CRC computation!
32    pub writer: T,
33    crc64: u64,
34}
35
36impl<T> CRC64Writer<T>
37where
38    T: Write,
39{
40    /// Create a new writer.
41    pub fn new(writer: T) -> Self {
42        CRC64Writer { crc64: 0, writer }
43    }
44
45    /// Returns the current checksum value.
46    pub fn checksum(&self) -> u64 {
47        self.crc64
48    }
49}
50
51impl<T> Write for CRC64Writer<T>
52where
53    T: Write,
54{
55    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
56        let bytes_written = self.writer.write(buf)?;
57        self.crc64 = crc64(self.crc64, &buf[..bytes_written]);
58        Ok(bytes_written)
59    }
60
61    fn flush(&mut self) -> std::io::Result<()> {
62        self.writer.flush()
63    }
64}
65
66#[cfg(test)]
67mod tests {
68    use super::{CRC64Writer, Write};
69
70    #[test]
71    fn test_crc_new() {
72        let mut buf = vec![0; 5];
73        let mut slice = buf.as_mut_slice();
74        let crc_writer = CRC64Writer::new(&mut slice);
75        assert_eq!(crc_writer.crc64, 0);
76        assert_eq!(crc_writer.writer, &[0; 5]);
77        assert_eq!(crc_writer.checksum(), 0);
78    }
79
80    #[test]
81    fn test_crc_write() {
82        let mut buf = vec![0; 16];
83        let write_buf = vec![123; 16];
84
85        let mut slice = buf.as_mut_slice();
86        let mut crc_writer = CRC64Writer::new(&mut slice);
87        crc_writer.write_all(write_buf.as_slice()).unwrap();
88        crc_writer.flush().unwrap();
89        assert_eq!(crc_writer.checksum(), 0x29D5_3572_1632_6566);
90        assert_eq!(crc_writer.checksum(), crc_writer.crc64);
91    }
92}