pub const CRC32_INIT: u32 = 0xFFFF_FFFF;
pub const CRC32_POLY: u32 = 0xEDB8_8320;
#[must_use]
pub fn crc32(bytes: &[u8]) -> u32 {
let table = build_table();
let mut crc = CRC32_INIT;
for &byte in bytes {
let idx = ((crc ^ u32::from(byte)) & 0xFF) as usize;
crc = (crc >> 8) ^ table[idx];
}
crc ^ CRC32_INIT
}
#[must_use]
pub fn build_table() -> [u32; 256] {
let mut table = [0u32; 256];
for (i, slot) in table.iter_mut().enumerate() {
let mut c = i as u32;
for _ in 0..8 {
c = if c & 1 == 1 {
(c >> 1) ^ CRC32_POLY
} else {
c >> 1
};
}
*slot = c;
}
table
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn crc32_empty_is_zero() {
assert_eq!(crc32(b""), 0);
}
#[test]
fn crc32_single_zero_byte() {
assert_eq!(crc32(&[0x00]), 0xD202_EF8D);
}
#[test]
fn crc32_nine_ones() {
assert_eq!(crc32(b"123456789"), 0xCBF4_3926);
}
#[test]
fn crc32_table_128_slot() {
let table = build_table();
assert_eq!(table[0], 0);
assert_eq!(table[1], 0x7707_3096);
}
}