windows-bindgen 0.66.0

Code generator for Windows metadata
Documentation
mod cfg;
mod cpp_handle;
mod format;
mod names;
mod value;

use super::*;
pub use cfg::*;

#[derive(Clone)]
pub struct Config<'a> {
    pub types: &'a TypeMap,
    pub references: &'a References,
    pub output: &'a str,
    pub flat: bool,
    pub no_allow: bool,
    pub no_comment: bool,
    pub no_deps: bool,
    pub no_toml: bool,
    pub package: bool,
    pub rustfmt: &'a str,
    pub sys: bool,
    pub sys_fn_ptrs: bool,
    pub sys_fn_extern: bool,
    pub implement: bool,
    pub specific_deps: bool,
    pub derive: &'a Derive,
    pub link: &'a str,
    pub warnings: &'a WarningBuilder,
    pub namespace: &'static str,
}

impl Config<'_> {
    pub fn with_namespace(&self, namespace: &'static str) -> Self {
        let mut clone = self.clone();
        clone.namespace = namespace;
        clone
    }
}

impl<'a> Config<'a> {
    #[track_caller]
    pub fn write(&self, tree: TypeTree) {
        if self.package {
            self.write_package(&tree);
        } else {
            self.write_file(tree);
        }
    }

    #[track_caller]
    fn write_file(&self, tree: TypeTree) {
        let tokens = if self.flat {
            self.write_flat(tree)
        } else {
            self.write_modules(&tree)
        };

        write_to_file(self.output, self.format(&tokens.into_string()));
    }

    fn write_flat(&self, tree: TypeTree) -> TokenStream {
        let mut tokens = TokenStream::new();

        for ty in tree.flatten_types() {
            tokens.combine(ty.write(self));
        }

        tokens
    }

    fn write_modules(&self, tree: &TypeTree) -> TokenStream {
        let mut tokens = TokenStream::new();

        for ty in &tree.types {
            tokens.combine(ty.write(self));
        }

        for (name, tree) in &tree.nested {
            let name = to_ident(name);
            let nested = self.with_namespace(tree.namespace).write_modules(tree);
            tokens.combine(quote! { pub mod #name { #nested } });
        }

        tokens
    }

    fn write_package(&self, tree: &TypeTree) {
        for name in tree.nested.keys() {
            _ = std::fs::remove_dir_all(format!("{}/src/{name}", &self.output));
        }

        let trees = tree.flatten_trees();

        for_each(trees.iter(), |tree| {
            let directory = format!("{}/src/{}", &self.output, tree.namespace.replace('.', "/"));

            let mut tokens = TokenStream::new();

            for (name, tree) in &tree.nested {
                let name = to_ident(name);
                let feature = tree.feature();

                tokens.combine(quote! {
                    #[cfg(feature = #feature)]
                    pub mod #name;
                });
            }

            let config = self.with_namespace(tree.namespace);

            for ty in &tree.types {
                tokens.combine(ty.write(&config));
            }

            let output = format!("{directory}/mod.rs");
            write_to_file(&output, self.format(&tokens.into_string()));
        });

        if self.no_toml {
            return;
        }

        let toml_path = format!("{}/Cargo.toml", &self.output);
        let mut toml = String::new();

        for line in read_file_lines(&toml_path) {
            toml.push_str(&line);
            toml.push('\n');

            if line == "# generated features" {
                break;
            }
        }

        for tree in trees.iter().skip(1) {
            let feature = tree.feature();

            if let Some(pos) = feature.rfind('_') {
                let dependency = &feature[..pos];

                toml.push_str(&format!("{feature} = [\"{dependency}\"]\n"));
            } else if namespace_starts_with(tree.namespace, "Windows.Win32")
                || namespace_starts_with(tree.namespace, "Windows.Wdk")
            {
                toml.push_str(&format!("{feature} = [\"Win32_Foundation\"]\n"));
            } else if tree.namespace != "Windows.Foundation" {
                toml.push_str(&format!("{feature} = [\"Foundation\"]\n"));
            } else {
                toml.push_str(&format!("{feature} = []\n"));
            }
        }

        write_to_file(&toml_path, toml);
    }
}

fn for_each<I, F, T>(i: I, f: F)
where
    I: Iterator<Item = T>,
    F: Fn(T) + Sync,
    T: Send,
{
    #[cfg(windows)]
    windows_threading::for_each(i, f);

    #[cfg(not(windows))]
    for item in i {
        f(item);
    }
}