const CRC8_TABLE: [u8; 256] = {
let mut table = [0u8; 256];
let mut i = 0;
while i < 256 {
let mut crc = i as u8;
let mut j = 0;
while j < 8 {
if crc & 0x80 != 0 {
crc = (crc << 1) ^ 0x07;
} else {
crc <<= 1;
}
j += 1;
}
table[i] = crc;
i += 1;
}
table
};
const CRC16_TABLE: [u16; 256] = {
let mut table = [0u16; 256];
let mut i = 0;
while i < 256 {
let mut crc = (i as u16) << 8;
let mut j = 0;
while j < 8 {
if crc & 0x8000 != 0 {
crc = (crc << 1) ^ 0x8005;
} else {
crc <<= 1;
}
j += 1;
}
table[i] = crc;
i += 1;
}
table
};
#[derive(Debug, Clone, Copy)]
pub struct Crc8 {
crc: u8,
}
impl Crc8 {
#[inline]
pub const fn new() -> Self {
Crc8 { crc: 0 }
}
#[inline]
pub fn update_byte(&mut self, byte: u8) {
self.crc = CRC8_TABLE[(self.crc ^ byte) as usize];
}
#[inline]
pub fn update(&mut self, data: &[u8]) {
for &byte in data {
self.update_byte(byte);
}
}
#[inline]
pub const fn finalize(self) -> u8 {
self.crc
}
#[inline]
pub fn reset(&mut self) {
self.crc = 0;
}
#[inline]
pub fn compute(data: &[u8]) -> u8 {
let mut crc = Self::new();
crc.update(data);
crc.finalize()
}
}
impl Default for Crc8 {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, Copy)]
pub struct Crc16 {
crc: u16,
}
impl Crc16 {
#[inline]
pub const fn new() -> Self {
Crc16 { crc: 0 }
}
#[inline]
pub fn update_byte(&mut self, byte: u8) {
self.crc = (self.crc << 8) ^ CRC16_TABLE[((self.crc >> 8) as u8 ^ byte) as usize];
}
#[inline]
pub fn update(&mut self, data: &[u8]) {
for &byte in data {
self.update_byte(byte);
}
}
#[inline]
pub const fn finalize(self) -> u16 {
self.crc
}
#[inline]
pub fn reset(&mut self) {
self.crc = 0;
}
#[inline]
pub fn compute(data: &[u8]) -> u16 {
let mut crc = Self::new();
crc.update(data);
crc.finalize()
}
}
impl Default for Crc16 {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_crc8_empty() {
assert_eq!(Crc8::compute(&[]), 0);
}
#[test]
fn test_crc8_single_byte() {
assert_eq!(Crc8::compute(&[0x00]), 0x00);
assert_eq!(Crc8::compute(&[0x01]), 0x07);
assert_eq!(Crc8::compute(&[0x02]), 0x0E);
}
#[test]
fn test_crc8_incremental() {
let data = [0x01, 0x02, 0x03, 0x04];
let single = Crc8::compute(&data);
let mut incremental = Crc8::new();
incremental.update(&data[..2]);
incremental.update(&data[2..]);
assert_eq!(single, incremental.finalize());
}
#[test]
fn test_crc16_empty() {
assert_eq!(Crc16::compute(&[]), 0);
}
#[test]
fn test_crc16_single_byte() {
assert_eq!(Crc16::compute(&[0x00]), 0x0000);
}
#[test]
fn test_crc16_incremental() {
let data = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08];
let single = Crc16::compute(&data);
let mut incremental = Crc16::new();
incremental.update(&data[..4]);
incremental.update(&data[4..]);
assert_eq!(single, incremental.finalize());
}
#[test]
fn test_crc8_reset() {
let mut crc = Crc8::new();
crc.update(&[0x01, 0x02]);
let first = crc.finalize();
crc.reset();
crc.update(&[0x01, 0x02]);
let second = crc.finalize();
assert_eq!(first, second);
}
#[test]
fn test_crc16_reset() {
let mut crc = Crc16::new();
crc.update(&[0x01, 0x02, 0x03]);
let first = crc.finalize();
crc.reset();
crc.update(&[0x01, 0x02, 0x03]);
let second = crc.finalize();
assert_eq!(first, second);
}
#[test]
fn test_crc8_table_generation() {
assert_eq!(CRC8_TABLE[0], 0);
let mut crc: u8 = 0x01;
for _ in 0..8 {
if crc & 0x80 != 0 {
crc = (crc << 1) ^ 0x07;
} else {
crc <<= 1;
}
}
assert_eq!(CRC8_TABLE[1], crc);
}
#[test]
fn test_crc16_table_generation() {
assert_eq!(CRC16_TABLE[0], 0);
let mut crc: u16 = 0x0100; for _ in 0..8 {
if crc & 0x8000 != 0 {
crc = (crc << 1) ^ 0x8005;
} else {
crc <<= 1;
}
}
assert_eq!(CRC16_TABLE[1], crc);
}
}