pub struct CRC32 {
crc: u32,
}
impl Default for CRC32 {
fn default() -> Self {
Self::new()
}
}
impl CRC32 {
const TABLE: [u32; 256] = Self::make_table();
pub fn new() -> Self {
Self { crc: 0xFFFFFFFF }
}
pub fn update_byte(&mut self, b: u8) {
self.crc = Self::TABLE[((self.crc ^ b as u32) & 0xFF) as usize] ^ (self.crc >> 8);
}
pub fn update(&mut self, buf: &[u8]) {
for &b in buf {
self.update_byte(b);
}
}
pub fn value(&self) -> u64 {
(self.crc ^ 0xFFFFFFFF) as u64
}
pub fn reset(&mut self) {
self.crc = 0xFFFFFFFF;
}
const fn make_table() -> [u32; 256] {
let mut table = [0u32; 256];
let mut i = 0u32;
while i < 256 {
let mut crc = i;
let mut j = 0;
while j < 8 {
if crc & 1 != 0 {
crc = (crc >> 1) ^ 0xEDB88320;
} else {
crc >>= 1;
}
j += 1;
}
table[i as usize] = crc;
i += 1;
}
table
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_empty() {
let crc = CRC32::new();
assert_eq!(crc.value(), 0);
}
#[test]
fn test_single_byte() {
let mut crc = CRC32::new();
crc.update_byte(0);
assert_eq!(crc.value(), 0xD202EF8D);
}
#[test]
fn test_check_value() {
let mut crc = CRC32::new();
crc.update(b"123456789");
assert_eq!(crc.value(), 0xCBF43926);
}
#[test]
fn test_hello() {
let mut crc = CRC32::new();
crc.update(b"hello");
assert_eq!(crc.value(), 0x3610A686);
}
#[test]
fn test_reset() {
let mut crc = CRC32::new();
crc.update(b"hello");
crc.reset();
assert_eq!(crc.value(), 0);
}
#[test]
fn test_incremental() {
let mut crc1 = CRC32::new();
crc1.update(b"hello world");
let mut crc2 = CRC32::new();
crc2.update(b"hello ");
crc2.update(b"world");
assert_eq!(crc1.value(), crc2.value());
}
#[test]
fn test_crc32_known_value() {
let mut crc = CRC32::new();
crc.update_byte(1);
crc.update_byte(2);
crc.update_byte(3);
assert_eq!(crc.value(), 1438416925);
}
#[test]
fn test_crc32_batch_vs_incremental() {
let mut batch = CRC32::new();
batch.update(&[1, 2, 3]);
let mut incremental = CRC32::new();
incremental.update_byte(1);
incremental.update_byte(2);
incremental.update_byte(3);
assert_eq!(batch.value(), incremental.value());
}
#[test]
fn test_crc32_reset_clears_state() {
let data = b"some bytes to checksum";
let mut crc = CRC32::new();
crc.update(data);
crc.reset();
crc.update(data);
let mut fresh = CRC32::new();
fresh.update(data);
assert_eq!(crc.value(), fresh.value());
}
#[test]
fn test_crc32_large_buffer() {
let buf: Vec<u8> = (0..1000).map(|i| (i % 256) as u8).collect();
let mut crc = CRC32::new();
crc.update(&buf);
assert_eq!(crc.value(), 1961098049);
}
#[test]
fn test_crc32_all_zero_bytes() {
let buf = [0u8; 256];
let mut crc = CRC32::new();
crc.update(&buf);
assert_eq!(crc.value(), 227968344);
}
#[test]
fn test_crc32_default() {
let crc = CRC32::default();
assert_eq!(crc.value(), 0);
}
}