rusteal_codegen/rust_gen/
mod.rs1pub mod enums;
4pub mod structs;
5pub mod classes;
6pub mod properties;
7pub mod delegates;
8pub mod module;
9pub mod func_ids;
10pub mod param_helpers;
11pub mod cargo_toml;
12pub mod manual;
13pub mod prelude;
14
15use std::collections::HashSet;
16use std::path::Path;
17
18use crate::context::CodegenContext;
19use crate::write_if_changed;
20
21pub fn generate(ctx: &CodegenContext, out_dir: &Path) {
23 std::fs::create_dir_all(out_dir).expect("Failed to create Rust output directory");
25 remove_disabled_modules(ctx, out_dir);
26
27 for module_name in ctx.enabled_modules.iter() {
29 let module_dir = out_dir.join(module_name);
30 std::fs::create_dir_all(&module_dir).expect("Failed to create module directory");
31 let mut written: HashSet<String> = HashSet::new();
34
35 if let Some(module_enums) = ctx.module_enums.get(module_name) {
37 for e in module_enums {
38 let code = enums::generate_enum(e);
39 let filename = crate::naming::to_snake_case(&e.name) + ".rs";
40 write_if_changed(&module_dir.join(&filename), &code)
41 .unwrap_or_else(|err| panic!("Failed to write {filename}: {err}"));
42 written.insert(filename);
43 }
44 }
45
46 if let Some(module_structs) = ctx.module_structs.get(module_name) {
48 for s in module_structs {
49 let code = structs::generate_struct(s, ctx);
50 let filename = crate::naming::to_snake_case(&s.name) + ".rs";
51 write_if_changed(&module_dir.join(&filename), &code)
52 .unwrap_or_else(|err| panic!("Failed to write {filename}: {err}"));
53 written.insert(filename);
54 }
55 }
56
57 if let Some(module_classes) = ctx.module_classes.get(module_name) {
59 for c in module_classes {
60 let code = classes::generate_class(c, ctx);
61 let filename = crate::naming::to_snake_case(&c.name) + ".rs";
62 write_if_changed(&module_dir.join(&filename), &code)
63 .unwrap_or_else(|err| panic!("Failed to write {filename}: {err}"));
64 written.insert(filename);
65 }
66 }
67
68 let mod_code = module::generate_module_mod(
70 module_name,
71 ctx.module_enums.get(module_name).map(|v| v.as_slice()),
72 ctx.module_structs.get(module_name).map(|v| v.as_slice()),
73 ctx.module_classes.get(module_name).map(|v| v.as_slice()),
74 );
75 write_if_changed(&module_dir.join("mod.rs"), &mod_code)
76 .expect("Failed to write module mod.rs");
77 written.insert("mod.rs".to_string());
78 remove_unwritten(&module_dir, &written);
79 }
80
81 let func_ids_code = func_ids::generate_rust_func_ids(&ctx.func_table);
83 write_if_changed(&out_dir.join("func_ids.rs"), &func_ids_code)
84 .expect("Failed to write func_ids.rs");
85
86 let lib_code = module::generate_lib_rs(ctx);
88 write_if_changed(&out_dir.join("lib.rs"), &lib_code).expect("Failed to write lib.rs");
89}
90
91fn remove_unwritten(module_dir: &Path, written: &HashSet<String>) {
93 let Ok(entries) = std::fs::read_dir(module_dir) else {
94 return;
95 };
96 for entry in entries.flatten() {
97 let name = entry.file_name().to_string_lossy().into_owned();
98 if written.contains(&name) {
99 continue;
100 }
101 let path = entry.path();
102 let removed = if path.is_dir() {
103 std::fs::remove_dir_all(&path)
104 } else {
105 std::fs::remove_file(&path)
106 };
107 removed.unwrap_or_else(|e| panic!("Failed to remove stale {}: {e}", path.display()));
108 }
109}
110
111fn remove_disabled_modules(ctx: &CodegenContext, out_dir: &Path) {
116 let Ok(entries) = std::fs::read_dir(out_dir) else {
117 return;
118 };
119 for entry in entries.flatten() {
120 let path = entry.path();
121 let name = entry.file_name().to_string_lossy().into_owned();
122 if !path.is_dir() || name == "manual" || ctx.enabled_modules.contains(&name) {
123 continue;
124 }
125 let generated = std::fs::read_to_string(path.join("mod.rs"))
126 .is_ok_and(|m| m.starts_with("// Auto-generated by rusteal-codegen."));
127 if generated {
128 std::fs::remove_dir_all(&path)
129 .unwrap_or_else(|e| panic!("Failed to remove {}: {e}", path.display()));
130 eprintln!(" removed {name}/ (module no longer enabled)");
131 }
132 }
133}