1use 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 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}