vbare_compiler/
lib.rs

1use indoc::formatdoc;
2use std::{fs, path::Path};
3
4/// Configuration for the vbare-compiler.
5///
6/// This allows callers to control how code generation behaves, including
7/// passing through configuration to `vbare_gen`.
8pub struct Config {
9    /// Configuration forwarded to `vbare_gen` for schema codegen.
10    pub vbare: vbare_gen::Config,
11}
12
13impl Default for Config {
14    fn default() -> Self {
15        Self {
16            vbare: vbare_gen::Config::with_hash_map(),
17        }
18    }
19}
20
21impl Config {
22    /// Convenience helper to enable hashable maps in generated code.
23    pub fn with_hashable_map() -> Self {
24        Self {
25            vbare: vbare_gen::Config::with_hashable_map(),
26        }
27    }
28
29    /// Convenience helper to use the standard library `HashMap`.
30    pub fn with_hash_map() -> Self {
31        Self {
32            vbare: vbare_gen::Config::with_hash_map(),
33        }
34    }
35}
36
37/// Process BARE schema files and generate Rust code.
38pub fn process_schemas(schema_dir: &Path) -> Result<(), Box<dyn std::error::Error>> {
39    process_schemas_with_config(schema_dir, &Config::default())
40}
41
42/// Process BARE schema files and generate Rust code, using the provided config.
43pub fn process_schemas_with_config(
44    schema_dir: &Path,
45    config: &Config,
46) -> Result<(), Box<dyn std::error::Error>> {
47    let out_dir = std::env::var("OUT_DIR")?;
48    let out_path = Path::new(&out_dir);
49
50    println!("cargo:rerun-if-changed={}", schema_dir.display());
51
52    let mut all_names = Vec::new();
53
54    for entry in fs::read_dir(schema_dir)?.flatten() {
55        let path = entry.path();
56
57        if path.is_dir() {
58            continue;
59        }
60
61        let bare_name = path
62            .file_name()
63            .ok_or("No file name")?
64            .to_str()
65            .ok_or("Invalid UTF-8 in file name")?
66            .rsplit_once('.')
67            .ok_or("No file extension")?
68            .0;
69
70        let tokens = vbare_gen::bare_schema(&path, config.vbare);
71        let ast = syn::parse2(tokens)?;
72        let content = prettyplease::unparse(&ast);
73
74        fs::write(out_path.join(format!("{bare_name}_generated.rs")), content)?;
75
76        all_names.push(bare_name.to_string());
77    }
78
79    let mut mod_content = String::new();
80    mod_content.push_str("// Auto-generated module file for schemas\n\n");
81
82    for name in all_names {
83        let module_name = name.replace('.', "_");
84        mod_content.push_str(&formatdoc!(
85            r#"
86            pub mod {module_name} {{
87                include!(concat!(env!("OUT_DIR"), "/{name}_generated.rs"));
88            }}
89            "#,
90            name = name,
91            module_name = module_name,
92        ));
93    }
94
95    fs::write(out_path.join("combined_imports.rs"), mod_content)?;
96
97    Ok(())
98}