use core::fmt::{self, Debug, Formatter};
#[derive(Clone)]
pub(crate) struct Checksum {
digest: crc::Digest<'static, u32>,
}
impl Checksum {
const ALGORITHM: crc::Algorithm<u32> = crc::CRC_32_ISCSI;
pub(crate) fn new() -> Self {
Self::with_seed(Self::ALGORITHM.init)
}
pub(crate) fn with_seed(seed: u32) -> Self {
const CRC32C: crc::Crc<u32> =
crc::Crc::<u32>::new(&Checksum::ALGORITHM);
Self {
digest: CRC32C.digest_with_initial(seed.reverse_bits()),
}
}
pub(crate) fn update(&mut self, data: &[u8]) {
self.digest.update(data);
}
pub(crate) fn update_u32_be(&mut self, data: u32) {
self.update(&data.to_be_bytes());
}
pub(crate) fn update_u16_le(&mut self, data: u16) {
self.update(&data.to_le_bytes());
}
pub(crate) fn update_u32_le(&mut self, data: u32) {
self.update(&data.to_le_bytes());
}
pub(crate) fn finalize(self) -> u32 {
self.digest.finalize() ^ (!0)
}
}
impl Debug for Checksum {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("Checksum").finish_non_exhaustive()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_checksum() {
let mut c = Checksum::new();
c.update_u32_le(1);
c.update_u32_le(2);
assert_eq!(c.finalize(), 0x858c13d3);
let mut c = Checksum::with_seed(123);
c.update_u32_le(1);
c.update_u32_le(2);
assert_eq!(c.finalize(), 0xfc527a0a);
assert_eq!(format!("{:?}", Checksum::new()), "Checksum { .. }");
}
}