const TABLE: [u16; 256] = {
let mut t = [0u16; 256];
let mut i = 0;
while i < 256 {
let mut c = (i as u16) << 8;
let mut j = 0;
while j < 8 {
if c & 0x8000 != 0 {
c = (c << 1) ^ 0x1021;
} else {
c <<= 1;
}
j += 1;
}
t[i] = c;
i += 1;
}
t
};
#[inline]
pub fn crc16_ccitt(bytes: &[u8]) -> u16 {
let mut crc: u16 = 0;
for &b in bytes {
let idx = ((crc >> 8) as u8 ^ b) as usize;
crc = (crc << 8) ^ TABLE[idx];
}
crc
}
#[cfg(test)]
mod tests {
use super::*;
fn reference(bytes: &[u8]) -> u16 {
let mut crc: u16 = 0;
for &b in bytes {
crc ^= (b as u16) << 8;
for _ in 0..8 {
if crc & 0x8000 != 0 {
crc = (crc << 1) ^ 0x1021;
} else {
crc <<= 1;
}
}
}
crc
}
#[test]
fn empty() {
assert_eq!(crc16_ccitt(&[]), 0);
}
#[test]
fn single_byte_zero() {
assert_eq!(crc16_ccitt(&[0x00]), 0x0000);
}
#[test]
fn standard_test_vector() {
assert_eq!(crc16_ccitt(b"123456789"), 0x31C3);
}
#[test]
fn matches_reference_over_many_lengths() {
let mut bytes = Vec::with_capacity(4096);
let mut state: u32 = 0x12345678;
for _ in 0..4096 {
state ^= state << 13;
state ^= state >> 17;
state ^= state << 5;
bytes.push(state as u8);
}
for len in [
0usize, 1, 2, 3, 15, 16, 17, 63, 64, 65, 511, 512, 513, 4095, 4096,
] {
assert_eq!(
crc16_ccitt(&bytes[..len]),
reference(&bytes[..len]),
"len={len}",
);
}
}
}