better_mimalloc_rs 0.1.0

A mimalloc wrapper that exposes tuning knobs and tracks the dev branch
Documentation
use std::env;
use std::fs;
use std::path::PathBuf;

#[derive(Clone, Copy)]
enum ValueKind {
    Bool,
    I64,
}

fn parse_bool(name: &str) -> Option<bool> {
    let raw = match env::var(name) {
        Ok(value) => value,
        Err(_) => return None,
    };
    let value = raw.trim().to_ascii_lowercase();
    match value.as_str() {
        "1" | "true" | "yes" | "on" => Some(true),
        "0" | "false" | "no" | "off" => Some(false),
        _ => panic!(
            "{}",
            format!("{name} must be 0/1/true/false/yes/no/on/off (got '{raw}')")
        ),
    }
}

fn parse_i64(name: &str) -> Option<i64> {
    let raw = match env::var(name) {
        Ok(value) => value,
        Err(_) => return None,
    };
    Some(
        raw.trim()
            .parse::<i64>()
            .ok()
            .unwrap_or_else(|| panic!("{}", format!("{name} must be an integer (got '{raw}')"))),
    )
}

fn main() {
    let entries: &[(&str, &str, ValueKind)] = &[
        ("MIMALLOC_CFG_EAGER_COMMIT", "BUILD_EAGER_COMMIT", ValueKind::Bool),
        (
            "MIMALLOC_CFG_EAGER_COMMIT_DELAY",
            "BUILD_EAGER_COMMIT_DELAY",
            ValueKind::I64,
        ),
        (
            "MIMALLOC_CFG_ARENA_EAGER_COMMIT",
            "BUILD_ARENA_EAGER_COMMIT",
            ValueKind::I64,
        ),
        (
            "MIMALLOC_CFG_PURGE_DECOMMITS",
            "BUILD_PURGE_DECOMMITS",
            ValueKind::Bool,
        ),
        (
            "MIMALLOC_CFG_PURGE_DELAY",
            "BUILD_PURGE_DELAY",
            ValueKind::I64,
        ),
        (
            "MIMALLOC_CFG_ARENA_PURGE_MULT",
            "BUILD_ARENA_PURGE_MULT",
            ValueKind::I64,
        ),
        (
            "MIMALLOC_CFG_PURGE_EXTEND_DELAY",
            "BUILD_PURGE_EXTEND_DELAY",
            ValueKind::I64,
        ),
        (
            "MIMALLOC_CFG_GENERIC_COLLECT",
            "BUILD_GENERIC_COLLECT",
            ValueKind::I64,
        ),
    ];

    for (env_name, _, _) in entries {
        println!("cargo:rerun-if-env-changed={env_name}");
    }

    let out_dir = PathBuf::from(env::var("OUT_DIR").expect("OUT_DIR not set"));
    let dest = out_dir.join("mimalloc_config.rs");

    let mut output = String::new();
    output.push_str("// @generated by build.rs. Do not edit.\n");

    for (env_name, const_name, kind) in entries {
        let rendered = match kind {
            ValueKind::Bool => match parse_bool(env_name) {
                Some(value) => format!("Some({})", value),
                None => "None".to_string(),
            },
            ValueKind::I64 => match parse_i64(env_name) {
                Some(value) => format!("Some({})", value),
                None => "None".to_string(),
            },
        };

        let ty = match kind {
            ValueKind::Bool => "Option<bool>",
            ValueKind::I64 => "Option<i64>",
        };

        output.push_str(&format!("pub const {const_name}: {ty} = {rendered};\n"));
    }

    fs::write(&dest, output).expect("failed to write mimalloc_config.rs");
}