Skip to main content

uika_codegen/rust_gen/
module.rs

1// Module file generation (mod.rs per module, lib.rs top-level).
2
3use crate::context::CodegenContext;
4use crate::naming::{is_reserved, to_snake_case};
5use crate::schema::{ClassInfo, EnumInfo, StructInfo};
6
7/// Generate a module's `mod.rs` with all sub-module declarations and re-exports.
8pub fn generate_module_mod(
9    _module_name: &str,
10    enums: Option<&[EnumInfo]>,
11    structs: Option<&[StructInfo]>,
12    classes: Option<&[ClassInfo]>,
13) -> String {
14    let mut out = String::with_capacity(4096);
15    out.push_str("// Auto-generated by uika-codegen. Do not edit.\n\n");
16
17    // Enum modules
18    if let Some(enums) = enums {
19        for e in enums {
20            let mod_name = to_snake_case(&e.name);
21            write_mod_use(&mut out, &mod_name);
22        }
23    }
24
25    // Struct modules
26    if let Some(structs) = structs {
27        for s in structs {
28            let mod_name = to_snake_case(&s.name);
29            write_mod_use(&mut out, &mod_name);
30        }
31    }
32
33    // Class modules
34    if let Some(classes) = classes {
35        for c in classes {
36            let mod_name = to_snake_case(&c.name);
37            write_mod_use(&mut out, &mod_name);
38        }
39    }
40
41    out
42}
43
44/// Write `mod foo; pub use foo::*;` handling keyword escaping.
45/// File on disk is named `foo.rs` but in code we use `r#foo` if needed.
46fn write_mod_use(out: &mut String, mod_name: &str) {
47    if is_reserved(mod_name) {
48        // Use #[path] attribute to map the keyword module name to its file
49        out.push_str(&format!("#[path = \"{mod_name}.rs\"]\n"));
50        out.push_str(&format!("mod r#{mod_name};\n"));
51        out.push_str(&format!("pub use r#{mod_name}::*;\n\n"));
52    } else {
53        out.push_str(&format!("mod {mod_name};\n"));
54        out.push_str(&format!("pub use {mod_name}::*;\n\n"));
55    }
56}
57
58/// Generate the top-level `lib.rs` with module declarations gated by features.
59pub fn generate_lib_rs(ctx: &CodegenContext) -> String {
60    let mut out = String::with_capacity(1024);
61    out.push_str("// Auto-generated by uika-codegen. Do not edit.\n\n");
62    out.push_str("#![allow(non_camel_case_types, non_snake_case, dead_code, unused_imports)]\n\n");
63    out.push_str("pub mod func_ids;\n\n");
64
65    // Sort modules for deterministic output
66    let mut modules: Vec<&String> = ctx.enabled_modules.iter().collect();
67    modules.sort();
68
69    for module in modules {
70        if let Some(feature) = ctx.feature_for_module(module) {
71            out.push_str(&format!(
72                "#[cfg(feature = \"{feature}\")]\npub mod {module};\n\n"
73            ));
74        } else {
75            out.push_str(&format!("pub mod {module};\n\n"));
76        }
77    }
78
79    // Hand-written manual override module (not generated).
80    out.push_str("pub mod manual;\n\n");
81
82    out
83}