const CRC16_POLY: u16 = 0b0001_0000_0010_0001;
#[repr(C)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Crc16(u16);
impl Crc16 {
pub const fn new() -> Self {
Self(0)
}
pub const fn bits(&self) -> u16 {
self.0
}
pub const fn calculate(buf: &[u8]) -> Self {
let len = buf.len();
let mut crc = 0u16;
let mut i = 0;
while i < len {
crc = Self::crc_table(crc ^ ((buf[i] as u16) << 8));
i = i.saturating_add(1);
}
Self(crc)
}
#[inline(always)]
const fn crc_table(mut crc: u16) -> u16 {
let mut j = 0usize;
while j < 8 {
crc = (crc << 1) ^ Self::crc_rem(crc);
j += 1;
}
crc
}
#[inline(always)]
const fn crc_rem(crc: u16) -> u16 {
if crc & 0x8000 != 0 { CRC16_POLY } else { 0 }
}
}
impl Default for Crc16 {
fn default() -> Self {
Self::new()
}
}
impl From<u16> for Crc16 {
fn from(val: u16) -> Self {
Self(val)
}
}
impl From<Crc16> for u16 {
fn from(val: Crc16) -> Self {
val.bits()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_crc16() {
[0x7fa1]
.map(Crc16::from)
.into_iter()
.zip([[0xff; 512]])
.for_each(|(exp_crc, data)| {
assert_eq!(Crc16::calculate(data.as_ref()), exp_crc);
});
}
}