xarxa-driver 0.1.0

Driver trait for the `xarxa` network stack.
Documentation
use std::collections::BTreeMap;
use std::fmt::Write;
use std::path::PathBuf;
use std::{env, fs};

static CONFIGS: &[(&str, usize)] = &[
    // BEGIN AUTOGENERATED CONFIG FEATURES
    // Generated by gen_config.py. DO NOT EDIT.
    ("PACKET_BUF_COUNT", 16),
    // END AUTOGENERATED CONFIG FEATURES
];

struct ConfigState {
    value: usize,
    seen_feature: bool,
    seen_env: bool,
}

fn main() {
    // only rebuild if build.rs changed. Otherwise Cargo will rebuild if any
    // other file changed.
    println!("cargo:rerun-if-changed=build.rs");

    // Rebuild if config envvar changed.
    for (name, _) in CONFIGS {
        println!("cargo:rerun-if-env-changed=XARXA_{name}");
    }

    let mut configs = BTreeMap::new();
    for (name, default) in CONFIGS {
        configs.insert(
            *name,
            ConfigState {
                value: *default,
                seen_env: false,
                seen_feature: false,
            },
        );
    }

    for (var, value) in env::vars() {
        if let Some(name) = var.strip_prefix("XARXA_") {
            // Unknown `XARXA_*` names are not an error here: they may be knobs
            // of the `xarxa` crate, whose build script checks them.
            let Some(cfg) = configs.get_mut(name) else { continue };

            let Ok(value) = value.parse::<usize>() else {
                panic!("Invalid value for env var {name}: {value}")
            };

            cfg.value = value;
            cfg.seen_env = true;
        }

        if let Some(feature) = var.strip_prefix("CARGO_FEATURE_")
            && let Some(i) = feature.rfind('_')
        {
            let name = &feature[..i];
            let value = &feature[i + 1..];
            if let Some(cfg) = configs.get_mut(name) {
                let Ok(value) = value.parse::<usize>() else {
                    panic!("Invalid value for feature {name}: {value}")
                };

                // envvars take priority.
                if !cfg.seen_env {
                    if cfg.seen_feature {
                        panic!("multiple values set for feature {}: {} and {}", name, cfg.value, value);
                    }

                    cfg.value = value;
                    cfg.seen_feature = true;
                }
            }
        }
    }

    let mut data = String::new();

    for (name, cfg) in &configs {
        writeln!(&mut data, "pub const {}: usize = {};", name, cfg.value).unwrap();
    }

    let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap());
    let out_file = out_dir.join("config.rs").to_string_lossy().to_string();
    fs::write(out_file, data).unwrap();
}