#![allow(clippy::unreadable_literal)]
#![allow(non_camel_case_types)]
//! Contains lists of models from
//! [Catalogue of parametrised CRC algorithms](https://reveng.sourceforge.io/crc-catalogue/all.htm).
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
/// The parameters that uniquely define a CRC.
/// Hopefully any CRC can be described with these parameters,
/// and then implemented in a parameterized way.
pub struct Model<T> {
/// Number of bits needed to store the CRC;
/// One less than the degree of the polynomial.
pub width: u32,
/// The generator polynomial `P(x) = a_i * x^i + a_(i-1) * x^(i-1) ... + a_0*x^0` for degree
/// `i`, where the LSB (bit 0) represents `a_0` and the MSB (bit `i-1`) represents `a_(i-1)`.
/// `a_i` is always one, so it is ommited (it wouldn't fit into `width` bits anyways).
pub poly: T,
/// The initial value, before reading the first message bit, in the same form as `poly`.
pub init: T,
/// If true, the characters of the input message are read bit-by-bit LSB first.
/// If false, the characters of the input message are read bit-by-bit MSB first.
pub refin: bool,
/// If true, the `width` bits of the register are reflected (order reversed) before applying
/// the final xor.
pub refout: bool,
/// The final xor to apply to the calculated crc after the message has been read and bits
/// optionaly reflected.
pub xorout: T,
/// The resulting checksum of the UTF-8 string "123456789".
pub check: T,
/// The crc of an error free code word without applyinf the final xor.
pub residue: T,
/// The name assigned to this model.
pub name: Option<&'static str>,
}
#[cfg(not(feature = "std"))]
use core::convert::TryFrom;
#[cfg(feature = "std")]
use std::convert::TryFrom;
// for each combination of two primitives, impl TryFrom
macro_rules! impl_alg_from {
(u128) => {}; // uint128 isn't crc_catalog::Width
($T:ident) => {
// if configured with the crc-catalog feature,
// add conversions between crc_catalog::Algorithm and fcrc::Model;
#[cfg(feature = "crc-catalog")]
impl From<crc_catalog::Algorithm<$T>> for Model<$T> {
fn from(value: crc_catalog::Algorithm<$T>) -> Self {
Model {
width: value.width.into(),
poly: value.poly,
init: value.init,
refin: value.refin,
refout: value.refout,
xorout: value.xorout,
check: value.check,
residue: value.residue,
name: None,
}
}
}
#[cfg(feature = "crc-catalog")]
impl From<Model<$T>> for crc_catalog::Algorithm<$T> {
fn from(value: Model<$T>) -> Self {
Self {
width: u8::try_from(value.width).expect("model bit width does not fit in u8"),
poly: value.poly,
init: value.init,
refin: value.refin,
refout: value.refout,
xorout: value.xorout,
check: value.check,
residue: value.residue,
}
}
}
// if test, then extern crc is available.
// add conversions between extern crc::Algorithm and fcrc::Model;
#[cfg(test)]
impl From<crc::Algorithm<$T>> for Model<$T> {
fn from(value: crc::Algorithm<$T>) -> Self {
Model {
width: <$T>::BITS,
poly: value.poly,
init: value.init,
refin: value.refin,
refout: value.refout,
xorout: value.xorout,
check: value.check,
residue: value.residue,
name: None,
}
}
}
#[cfg(test)]
impl TryFrom<Model<$T>> for crc::Algorithm<$T> {
type Error = &'static str;
fn try_from(value: Model<$T>) -> Result<Self, Self::Error> {
if <$T>::BITS != value.width {
return Err("width is not exactly word size");
}
Ok(Self {
poly: value.poly,
init: value.init,
refin: value.refin,
refout: value.refout,
xorout: value.xorout,
check: value.check,
residue: value.residue,
})
}
}
};
($T:ident => $U:ident) => {
// add conversion between Models for pairs of primitives
impl TryFrom<Model<$T>> for Model<$U> {
type Error = &'static str;
fn try_from(value: Model<$T>) -> Result<Self, Self::Error> {
if value.width > <$U>::BITS {
return Err("width does not fit");
}
Ok(Model {
width: value.width,
poly: <$U>::try_from(value.poly).map_err(|_| "poly does not fit")?,
init: <$U>::try_from(value.init).map_err(|_| "init does not fit")?,
refin: value.refin,
refout: value.refout,
xorout: <$U>::try_from(value.xorout).map_err(|_| "xorout does not fit")?,
check: <$U>::try_from(value.check).map_err(|_| "check does not fit")?,
residue: <$U>::try_from(value.residue).map_err(|_| "residue does not fit")?,
name: value.name,
})
}
}
};
($A:ident, $($rest:ident),+) => {
// Take the list of primitives and turn it into pairs.
// Lists all 2-combinations of the list,
// and then each individual element.
$(
impl_alg_from!($A => $rest);
impl_alg_from!($rest => $A);
)*
impl_alg_from!($A);
impl_alg_from!($($rest),*);
};
}
impl_alg_from!(u8, u16, u32, u64, u128);
// include the generated list of models.
// This is generated from build/generate_models.rs
#[path = "generated_models.rs"]
mod generated_models;
pub use generated_models::*;