use crate::util::reverse;
mod parse;
#[derive(Clone)]
pub struct Spec {
pub width: u16,
pub poly: u128,
pub init: u128,
pub refin: bool,
pub refout: bool,
pub xorout: u128,
pub check: u128,
pub residue: u128,
pub name: String,
}
impl Spec {
pub fn reflect(&self) -> bool {
self.refin
}
pub fn reverse(&self) -> bool {
self.refin ^ self.refout
}
pub fn init(&self) -> u128 {
let maybe_reversed = if self.refout {
reverse(self.init, self.width)
} else {
self.init
};
maybe_reversed ^ self.xorout
}
pub fn poly(&self) -> u128 {
if self.refin {
reverse(self.poly, self.width)
} else {
self.poly
}
}
}
impl core::str::FromStr for Spec {
type Err = parse::SpecParseError;
fn from_str(s: &str) -> Result<Spec, parse::SpecParseError> {
parse::read_spec(s)
}
}
impl core::fmt::Display for Spec {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
if f.alternate() {
write!(
f,
"w={width} p={poly}{init} r={refin}{refout}{xorout} c={check}{residue} n={name}",
width = self.width,
poly = self.poly,
init = if self.init == 0 {
"".into()
} else {
format!("i={}", self.init)
},
refin = if self.refin { "t" } else { "f" },
refout = if self.refout == self.refin {
"".into()
} else {
format!("refo={}", if self.refout { "t" } else { "f" })
},
xorout = if self.xorout == 0 {
"".into()
} else {
format!("x={}", self.xorout)
},
check = self.check,
residue = if self.residue == 0 {
"".into()
} else {
format!("res={}", self.residue)
},
name = self.name,
)
} else {
write!(
f,
"width={width} poly={poly:#06x} init={init:#06x} refin={refin} refout={refout} xorout={xorout:#06x} check={check:#06x} residue={residue:#06x} name={name:?}",
width = self.width,
poly = self.poly,
init = self.init,
refin = self.refin,
refout = self.refout,
xorout = self.xorout,
check = self.check,
residue = self.residue,
name = self.name,
)
}
}
}
#[cfg(test)]
mod test {
use super::*;
const KERMIT_FULL: &str = "width=16 poly=0x1021 init=0x0000 refin=true refout=true xorout=0x0000 check=0x2189 residue=0x0000 name=\"KERMIT\"";
const KERMIT_ABBR: &str = "w=16 p=4129 r=t c=8585 n=KERMIT";
#[test]
fn kermit_full() {
let model = KERMIT_FULL.parse::<Spec>().unwrap();
assert_eq!(KERMIT_FULL, format!("{}", model));
assert_eq!(KERMIT_ABBR, format!("{:#}", model));
assert_eq!(16, model.width);
assert_eq!(0x1021, model.poly);
assert_eq!(0, model.init);
assert!(model.refin);
assert!(model.refout);
assert_eq!(0, model.xorout);
assert_eq!(0x2189, model.check);
assert_eq!(0, model.residue);
assert_eq!("KERMIT", model.name);
}
#[test]
fn kermit_abbr() {
let model = KERMIT_ABBR.parse::<Spec>().unwrap();
assert_eq!(KERMIT_FULL, format!("{}", model));
assert_eq!(KERMIT_ABBR, format!("{:#}", model));
assert_eq!(16, model.width);
assert_eq!(0x1021, model.poly);
assert_eq!(0, model.init);
assert!(model.refin);
assert!(model.refout);
assert_eq!(0, model.xorout);
assert_eq!(0x2189, model.check);
assert_eq!(0, model.residue);
assert_eq!("KERMIT", model.name);
}
}