#[cfg(not(feature = "generate-models"))] fn main() {} #[cfg(feature = "generate-models")] fn main() -> Result<(), Box> { // Scrape the site of CRC RevEng, and arbitrary precision CRC calculator and algorithm finder. // The code is GPLv3+ however the the list of parameterized CRC's appears to be public domain. // Where this is only scraped ocasionally (then the generated content is distributed) // I think that's fine. It's also what the crate `crc_catalog` does. let req = reqwest::blocking::get("https://reveng.sourceforge.io/crc-catalogue/all.htm")?; let req = req.text()?; println!("Req is {:?}", &req); generate_models(&req, true, std::fs::File::create("src/generated_models.rs")?, "pub const", |n| format!("Some({:?})", n))?; generate_models(&req, false, std::fs::File::create("src/generated_models_c_api.rs")?, "#[no_mangle]\npub static", |n| format!("\"{}\\0\".as_ptr()", n))?; Ok(()) } #[cfg(feature = "generate-models")] fn generate_models(req: &str, gen_128: bool, mut out: impl std::io::Write, decl: &str, get_name: impl Fn(&str) -> String) -> Result<(), Box> { // width=5 poly=0x05 init=0x1f refin=true refout=true xorout=0x1f check=0x19 residue=0x06 name="CRC-5/USB" let re = regex::Regex::new( r#"width=(\S+)\s+poly=(\S+)\s+init=(\S+)\s+refin=(\S+)\s+refout=(\S+)\s+xorout=(\S+)\s+check=(\S+)\s+residue=(\S+)\s+name="([^"]+)""#)?; writeln!(out, "// generated by build/generate_models.rs")?; writeln!(out, "use super::Model;")?; writeln!(out, "/// CRC-8 Model\npub type Model_u8 = Model;")?; writeln!(out, "/// CRC-16 Model\npub type Model_u16 = Model;")?; writeln!(out, "/// CRC-32 Model\npub type Model_u32 = Model;")?; writeln!(out, "/// CRC-64 Model\npub type Model_u64 = Model;")?; writeln!(out, "/// CRC-128 Model\npub type Model_u128 = Model;")?; let mut all8: Vec = vec![]; let mut all16: Vec = vec![]; let mut all32: Vec = vec![]; let mut all64: Vec = vec![]; let mut all128: Vec = vec![]; for cap in re.captures_iter(req) { println!("Writing constant for {:?}", &cap[9]); let safe_name = cap[9].replace(|c| match c { 'a'..='z'|'A'..='Z'|'0'..='9' => false, _ => true }, "_"); let width: u32 = cap[1].parse()?; let typ = match width { 1..=8 => { all8.push(safe_name.clone()); "Model_u8" }, 9..=16 => { all16.push(safe_name.clone()); "Model_u16" }, 17..=32 => { all32.push(safe_name.clone()); "Model_u32" }, 33..=64 => { all64.push(safe_name.clone()); "Model_u64" }, 65..=128 if gen_128 => { all128.push(safe_name.clone()); "Model_u128" }, _ => { eprintln!("skipping {:?} because {} is too wide", &cap[9], width); continue; }, }; let name = get_name(&cap[9]); write!(out, "/// Describes {:?} \n{} {}: {} = {} {{ width: {}, poly: {}, init: {}, refin: {}, refout: {}, xorout: {}, check: {}, residue: {}, name: {}}};\n", &cap[9], decl, safe_name, typ, typ, &cap[1], &cap[2], &cap[3], &cap[4], &cap[5], &cap[6], &cap[7], &cap[8], name )?; } write!(out, "\n/// A list of models that operate on the `u8` primitive.\n{} ALL_CRC_8: [Model_u8;{}] = [\n", decl, all8.len())?; for n in &all8 { write!(out, "\t{},\n", n)?; } write!(out, "];")?; write!(out, "\n/// A list of models that operate on the `u16` primitive.\n{} ALL_CRC_16: [Model_u16;{}] = [\n", decl, all16.len())?; for n in &all16 { write!(out, "\t{},\n", n)?; } write!(out, "];")?; write!(out, "\n/// A list of models that operate on the `u32` primitive.\n{} ALL_CRC_32: [Model_u32;{}] = [\n", decl, all32.len())?; for n in &all32 { write!(out, "\t{},\n", n)?; } write!(out, "];")?; write!(out, "\n/// A list of models that operate on the `u64` primitive.\n{} ALL_CRC_64: [Model_u64;{}] = [\n", decl, all64.len())?; for n in &all64 { write!(out, "\t{},\n", n)?; } write!(out, "];")?; if gen_128 { write!(out, "\n/// A list of models that operate on the `u128` primitive.\n{} ALL_CRC_128: [Model_u128;{}] = [\n", decl, all128.len())?; for n in &all128 { write!(out, "\t{},\n", n)?; } write!(out, "];")?; } Ok(()) }