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