w2c2-sys 0.1.0

bindgen wrapper for w2c2
Documentation
use std::{env, path::PathBuf};

use glob::glob;
use miette::IntoDiagnostic;

#[cfg(feature = "bindgen")]
use bindgen::callbacks::{DeriveInfo, TypeKind};

#[cfg(feature = "bindgen")]
use miette::WrapErr;

#[cfg(feature = "bindgen")]
#[derive(Debug)]
struct AddDeriveCallbacks;

#[cfg(feature = "bindgen")]
impl bindgen::callbacks::ParseCallbacks for AddDeriveCallbacks {
    fn add_derives(&self, info: &DeriveInfo<'_>) -> Vec<String> {
        let mut ret = vec![];

        match info.kind {
            TypeKind::Struct | TypeKind::Enum if !["WasmConstInstruction"].contains(&info.name) => {
                ret.push("ConstDefault".to_string());
            }
            _ => {}
        }

        match info.kind {
            TypeKind::Struct if !["WasmConstInstruction"].contains(&info.name) => {
                ret.push("TypedBuilder".to_string());
            }
            _ => {}
        }

        ret
    }
}

#[cfg(feature = "bindgen")]
fn do_bindgen<I: IntoIterator>(headers: I, file: &str) -> miette::Result<PathBuf>
where
    I::Item: Into<String>,
{
    let out_path: PathBuf = PathBuf::from("./src");

    let bindings = bindgen::Builder::default()
        .headers(headers)
        .clang_args(["-Wno-incompatible-pointer-types", "-Wno-pointer-sign"])
        .clang_args([
            "-D__bool_true_false_are_defined",
            "-Dbool=_Bool",
            "-Dfalse=0",
            "-Dtrue=1",
        ])
        .allowlist_item(format!(
            "([wW]asm|[bB]uffer|[aA]rray|readFile|stringBuilder).*"
        ))
        .use_core()
        .derive_copy(true)
        .derive_hash(true)
        .generate_cstr(true)
        .array_pointers_in_arguments(true)
        .sort_semantically(true)
        .merge_extern_blocks(true)
        .layout_tests(false)
        .wrap_static_fns(true)
        .wrap_static_fns_path(out_path.join("out"))
        .newtype_enum(".*")
        .default_macro_constant_type(bindgen::MacroTypeVariation::Signed)
        .parse_callbacks(Box::new(AddDeriveCallbacks))
        .parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
        .generate()
        .into_diagnostic()?;

    bindings
        .write_to_file(out_path.join(file))
        .into_diagnostic()
        .wrap_err("Failed to write bindgen result")?;

    Ok(out_path.join(file))
}

fn build_static_library() -> miette::Result<()> {
    let out_path: PathBuf = PathBuf::from("./src");
    let manifest_path: PathBuf = env::var("CARGO_MANIFEST_DIR").into_diagnostic()?.into();
    let mut cc = cc::Build::new();

    let sources = glob("./w2c2/w2c2/*.c")
        .into_diagnostic()?
        .filter_map(Result::ok)
        .filter(|x| {
            if let Some(file) = x.file_stem()
                && let Some(file) = file.to_str()
            {
                if file.ends_with("test") {
                    return false;
                }
                if file == "main" {
                    return false;
                }
            }
            true
        });

    let cc = cc
        .define("__bool_true_false_are_defined", None)
        .define("bool", "_Bool")
        .define("false", "0")
        .define("true", "1")
        .files(sources)
        .file(out_path.join("out.c"))
        .includes([
            manifest_path.canonicalize().into_diagnostic()?,
            manifest_path
                .join("./w2c2/w2c2")
                .canonicalize()
                .into_diagnostic()?,
        ]);

    cc.try_compile("libw2c2").into_diagnostic()?;
    Ok(())
}

fn main() -> miette::Result<()> {
    #[cfg(feature = "bindgen")]
    {
        let headers = glob("./w2c2/w2c2/*.h")
            .into_diagnostic()?
            .filter_map(Result::ok)
            .filter(|x| {
                if let Some(file) = x.file_stem()
                    && let Some(file) = file.to_str()
                {
                    if file.ends_with("test") {
                        return false;
                    }
                    if file == "main" {
                        return false;
                    }
                }
                return true;
            })
            .map(|x| x.display().to_string());

        let _out_path = do_bindgen(headers, "wrapper.rs")?;
        // generate_mid_level_binding(out_path)?;
    }
    let _ = build_static_library();
    Ok(())
}