fcrc 0.1.0

Fast-CRC is a generic CRC implementation using SIMD instructions when available and a fallback when not.
Documentation


#[cfg(not(feature = "generate-models"))]
fn main() {}

#[cfg(feature = "generate-models")]
fn main() -> Result<(), Box<dyn std::error::Error>> {

    // 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<dyn std::error::Error>> {

    //     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<u8>;")?;
    writeln!(out, "/// CRC-16 Model\npub type Model_u16 = Model<u16>;")?;
    writeln!(out, "/// CRC-32 Model\npub type Model_u32 = Model<u32>;")?;
    writeln!(out, "/// CRC-64 Model\npub type Model_u64 = Model<u64>;")?;
    writeln!(out, "/// CRC-128 Model\npub type Model_u128 = Model<u128>;")?;
    
    let mut all8: Vec<String> = vec![];
    let mut all16: Vec<String> = vec![];
    let mut all32: Vec<String> = vec![];
    let mut all64: Vec<String> = vec![];
    let mut all128: Vec<String> = 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(())
}