use crc_fast::CrcAlgorithm;
#[inline]
pub fn crc32c(bytes: &[u8]) -> u32 {
crc_fast::crc32_iscsi(bytes) as u32
}
#[inline]
pub fn crc32c_append(prev: u32, bytes: &[u8]) -> u32 {
let suffix = crc_fast::crc32_iscsi(bytes) as u64;
crc_fast::checksum_combine(
CrcAlgorithm::Crc32Iscsi,
prev as u64,
suffix,
bytes.len() as u64,
) as u32
}
#[cfg(test)]
mod tests {
use std::iter::repeat_n;
use super::*;
#[test]
fn empty_input_is_zero() {
assert_eq!(crc32c(b""), 0);
}
#[test]
fn single_byte_known_vector() {
assert_eq!(crc32c(b"a"), 0xC1D0_4330);
}
#[test]
fn ascii_string_known_vector() {
assert_eq!(crc32c(b"123456789"), 0xE306_9283);
}
#[test]
fn append_matches_one_shot() {
let bytes: &[u8] = b"the quick brown fox jumps over the lazy dog";
let one_shot = crc32c(bytes);
let mut acc = 0u32;
for chunk in bytes.chunks(7) {
acc = crc32c_append(acc, chunk);
}
assert_eq!(acc, one_shot);
let mut acc2 = 0u32;
for chunk in bytes.chunks(1) {
acc2 = crc32c_append(acc2, chunk);
}
assert_eq!(acc2, one_shot);
}
#[test]
fn append_with_zero_seed_equals_one_shot() {
assert_eq!(crc32c_append(0, b"hello"), crc32c(b"hello"));
}
#[test]
fn alignment_does_not_affect_result() {
let buf: Vec<u8> = (0..1024u16).map(|i| i as u8).collect();
let baseline = crc32c(&buf);
for shift in 1..16 {
let shifted: Vec<u8> = repeat_n(0u8, shift).chain(buf.iter().copied()).collect();
assert_eq!(crc32c(&shifted[shift..]), baseline);
}
}
#[test]
fn different_inputs_give_different_outputs() {
let a = crc32c(b"AAAA");
let b = crc32c(b"AAAB");
assert_ne!(a, b);
}
#[test]
fn large_input_does_not_panic_or_truncate() {
let big: Vec<u8> = (0..4_000_000).map(|i| (i % 256) as u8).collect();
let _ = crc32c(&big);
}
}