use crate::crc::Crc;
use crate::spec::Spec;
use crate::util::{ones, reverse};
pub struct BitwiseModel {
spec: Spec,
reflect: bool,
reverse: bool,
poly: u128,
init: u128,
}
impl BitwiseModel {
pub fn reflect(&self) -> bool {
self.reflect
}
pub fn reverse(&self) -> bool {
self.reverse
}
pub fn width(&self) -> u16 {
self.spec.width
}
pub fn init(&self) -> u128 {
self.init as _
}
pub fn xorout(&self) -> u128 {
self.spec.xorout
}
pub fn from_spec(spec: Spec) -> BitwiseModel {
let poly = if spec.refin {
reverse(spec.poly, spec.width)
} else {
spec.poly
};
let init = spec.xorout
^ if spec.refout {
reverse(spec.init, spec.width)
} else {
spec.init
};
let reflect = spec.refin;
let reverse = spec.refin ^ spec.refout;
BitwiseModel {
spec,
reflect,
reverse,
poly,
init,
}
}
}
impl Crc for BitwiseModel {
type Int = u128;
fn init(&self) -> u128 {
self.init as _
}
fn add_bytes(&self, mut crc: u128, data: &[u8]) -> u128 {
if data.is_empty() {
return crc;
}
crc ^= self.spec.xorout;
if self.reverse {
crc = reverse(crc, self.spec.width);
}
if self.reflect {
crc &= ones(self.spec.width);
for byte in data {
crc ^= *byte as u128;
for _ in 0..8 {
crc = if crc & 1 != 0 {
(crc >> 1) ^ self.poly
} else {
crc >> 1
};
}
}
} else if self.spec.width <= 8 {
let shift = 8 - self.spec.width;
let poly = self.poly << shift;
crc <<= shift;
for byte in data {
crc ^= *byte as u128;
for _ in 0..8 {
crc = if crc & 0x80 != 0 {
(crc << 1) ^ poly
} else {
crc << 1
};
}
}
crc >>= shift;
crc &= ones(self.spec.width);
} else {
let mask = 1 << (self.spec.width - 1);
let shift = self.spec.width - 8;
for byte in data {
crc ^= (*byte as u128) << shift;
for _ in 0..8 {
crc = if crc & mask != 0 {
(crc << 1) ^ self.poly
} else {
crc << 1
};
}
}
crc &= ones(self.spec.width);
}
if self.reverse {
crc = reverse(crc, self.spec.width);
}
crc ^= self.spec.xorout;
crc as _
}
}