nydus_utils/
crc32.rs

1// Copyright 2025 Nydus Developers. All rights reserved.
2//
3// SPDX-License-Identifier: Apache-2.0
4
5use crc::Crc;
6use crc::Table;
7use std::fmt;
8use std::fmt::Debug;
9use std::io::Read;
10
11#[repr(u32)]
12#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
13pub enum Algorithm {
14    None = 0,
15    #[default]
16    Crc32Iscsi = 1,
17}
18
19impl fmt::Display for Algorithm {
20    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
21        write!(f, "{:?}", self)
22    }
23}
24
25impl TryFrom<u32> for Algorithm {
26    type Error = ();
27
28    fn try_from(value: u32) -> Result<Self, Self::Error> {
29        if value == Algorithm::None as u32 {
30            Ok(Algorithm::None)
31        } else if value == Algorithm::Crc32Iscsi as u32 {
32            Ok(Algorithm::Crc32Iscsi)
33        } else {
34            Err(())
35        }
36    }
37}
38
39impl TryFrom<u64> for Algorithm {
40    type Error = ();
41
42    fn try_from(value: u64) -> Result<Self, Self::Error> {
43        if value == Algorithm::None as u64 {
44            Ok(Algorithm::None)
45        } else if value == Algorithm::Crc32Iscsi as u64 {
46            Ok(Algorithm::Crc32Iscsi)
47        } else {
48            Err(())
49        }
50    }
51}
52
53pub struct Crc32 {
54    crc: Crc<u32, Table<16>>,
55}
56
57impl Default for Crc32 {
58    fn default() -> Self {
59        Self::new(Algorithm::Crc32Iscsi)
60    }
61}
62
63impl Crc32 {
64    pub fn new(algorithm: Algorithm) -> Self {
65        let crc = match algorithm {
66            Algorithm::Crc32Iscsi => &crc::CRC_32_ISCSI,
67            _ => &crc::CRC_32_ISCSI,
68        };
69        Self {
70            crc: Crc::<u32, Table<16>>::new(crc),
71        }
72    }
73
74    pub fn from_buf(&self, bytes: &[u8]) -> u32 {
75        self.crc.checksum(bytes)
76    }
77
78    /// Compute message crc32 by read data from the reader.
79    pub fn from_reader<R: Read>(&self, reader: &mut R) -> std::io::Result<u32> {
80        let mut digester = self.crc.digest();
81        let mut buf = vec![0u8; 1024 * 1024];
82        loop {
83            let sz = reader.read(&mut buf)?;
84            if sz == 0 {
85                return Ok(digester.finalize());
86            }
87            digester.update(&buf[0..sz]);
88        }
89    }
90}
91
92#[cfg(test)]
93mod tests {
94    use super::*;
95
96    #[test]
97    fn test_crc32_from_buf() {
98        let crc32 = Crc32::new(Algorithm::Crc32Iscsi);
99        let data = b"123456789";
100        let expected_checksum = 0xe3069283;
101        let crc32_result = crc32.from_buf(data);
102        assert_eq!(crc32_result, expected_checksum);
103    }
104
105    #[test]
106    fn test_crc32_from_reader() {
107        let crc32 = Crc32::new(Algorithm::Crc32Iscsi);
108        let data = b"123456789";
109        let expected_checksum = 0xe3069283;
110        let mut reader = std::io::Cursor::new(data);
111        let crc32_result = crc32.from_reader(&mut reader).unwrap();
112        assert_eq!(crc32_result, expected_checksum);
113    }
114}