use byteorder::ByteOrder;
use crate::crc::Crc;
use crate::model::BytewiseModel;
use crate::spec::Spec;
use crate::util::{ones, reverse};
pub struct WordwiseModel<Endianness: byteorder::ByteOrder, const WORD_BITS: u16> {
model: BytewiseModel,
pub table: [[u128; 256]; 8],
_endianness: core::marker::PhantomData<Endianness>,
}
trait TableFiller {
fn fill_table(&mut self);
fn swap(&self) -> bool;
}
impl<const WORD_BITS: u16> TableFiller for WordwiseModel<byteorder::LittleEndian, WORD_BITS> {
fn fill_table(&mut self) {
self.fill_table_kernel(self.swap());
}
fn swap(&self) -> bool {
!self.model.reflect()
}
}
impl<const WORD_BITS: u16> TableFiller for WordwiseModel<byteorder::BigEndian, WORD_BITS> {
fn fill_table(&mut self) {
self.fill_table_kernel(self.swap());
}
fn swap(&self) -> bool {
self.model.reflect()
}
}
impl<const WORD_BITS: u16> WordwiseModel<byteorder::LittleEndian, WORD_BITS> {
pub fn from_spec(spec: Spec) -> Self {
let mut me = WordwiseModel::from_spec_kernel(spec);
me.fill_table();
me
}
}
impl<const WORD_BITS: u16> WordwiseModel<byteorder::BigEndian, WORD_BITS> {
pub fn from_spec(spec: Spec) -> Self {
let mut me = WordwiseModel::from_spec_kernel(spec);
me.fill_table();
me
}
}
impl Crc for WordwiseModel<byteorder::NativeEndian, { usize::BITS as _ }> {
type Int = u128;
fn init(&self) -> u128 {
self.model.init()
}
fn add_bytes(&self, mut crc: u128, data: &[u8]) -> u128 {
if data.is_empty() {
return crc;
}
let top = self.top();
let shift = if self.model.width() <= 8 {
8 - self.model.width()
} else {
self.model.width() - 8
};
if self.model.reverse() {
crc = reverse(crc, self.model.width());
}
let word_bytes = usize::BITS >> 3;
let mut shifted = false;
if self.model.reflect() {
crc &= ones(self.model.width());
} else if self.model.width() <= 8 {
crc <<= shift;
}
let mut iter = data.iter().copied();
loop {
let mut next = vec![];
for _ in 0..word_bytes {
if let Some(c) = iter.next() {
next.push(c);
}
}
if next.len() == word_bytes as _ {
if !shifted {
crc <<= top;
if self.swap() {
crc = (crc as usize).swap_bytes() as _;
}
shifted = true;
}
crc ^= byteorder::NativeEndian::read_uint128(&next[..], word_bytes as _);
assert_eq!(word_bytes, 8);
crc = self.table[(word_bytes - 1) as usize][(crc as u8) as usize]
^ self.table[(word_bytes - 2) as usize][((crc >> 8) as u8) as usize]
^ self.table[(word_bytes - 3) as usize][((crc >> 16) as u8) as usize]
^ self.table[(word_bytes - 4) as usize][((crc >> 24) as u8) as usize]
^ self.table[(word_bytes - 5) as usize][((crc >> 32) as u8) as usize]
^ self.table[(word_bytes - 6) as usize][((crc >> 40) as u8) as usize]
^ self.table[(word_bytes - 7) as usize][((crc >> 48) as u8) as usize]
^ self.table[(word_bytes - 8) as usize][((crc >> 56) as u8) as usize];
} else if next.is_empty() {
break;
} else {
if shifted {
if self.swap() {
crc = (crc as usize).swap_bytes() as _;
}
crc >>= top;
shifted = false;
}
if self.model.reflect() {
for byte in next {
let byte = byte as u128;
crc = (crc >> 8) ^ self.model.table[((crc ^ byte) as u8) as usize];
}
} else if self.model.width() <= 8 {
for byte in next {
let byte = byte as u128;
crc = self.model.table[((crc ^ byte) as u8) as usize];
}
crc >>= shift;
} else {
for byte in next {
let byte = byte as u128;
crc =
(crc << 8) ^ self.model.table[(((crc >> shift) ^ byte) as u8) as usize];
}
crc &= ones(self.model.width());
}
break;
}
}
if shifted {
if self.swap() {
crc = crc.swap_bytes();
}
crc >>= top;
}
if !self.model.reflect() && self.model.width() > 8 {
crc &= ones(self.model.width());
}
if self.model.reverse() {
crc = reverse(crc, self.model.width());
}
crc as _
}
}
impl<Endianness: byteorder::ByteOrder, const WORD_BITS: u16> WordwiseModel<Endianness, WORD_BITS> {
fn from_spec_kernel(spec: Spec) -> WordwiseModel<Endianness, WORD_BITS> {
WordwiseModel {
model: BytewiseModel::from_spec(spec),
table: [[0; 256]; 8],
_endianness: core::marker::PhantomData,
}
}
fn top(&self) -> u16 {
if self.model.reflect() {
0
} else {
WORD_BITS
- (if self.model.width() > 8 {
self.model.width()
} else {
8
})
}
}
fn fill_table_kernel(&mut self, swap: bool) {
let top = self.top();
let mut xor = self.model.xorout();
if self.model.width() < 8 && !self.model.reflect() {
xor <<= 8 - self.model.width();
}
for k in 0..256 {
let mut crc = self.model.table[k];
self.table[0][k] = if swap {
((crc << top) as usize).swap_bytes() as _ } else {
crc << top
};
for n in 1..(WORD_BITS as usize >> 3) {
crc ^= xor;
if self.model.reflect() {
crc = (crc >> 8) ^ self.model.table[(crc as u8) as usize];
} else if self.model.width() <= 8 {
crc = self.model.table[(crc as u8) as usize];
} else {
crc = (crc << 8)
^ self.model.table[((crc >> (self.model.width() - 8)) as u8) as usize];
}
crc ^= xor;
self.table[n][k] = if swap {
((crc << top) as usize).swap_bytes() as _ } else {
crc << top
};
}
}
}
}