1use std::collections::{BTreeMap, HashMap, HashSet};
4
5use crate::config::CodegenConfig;
6use crate::schema::{ClassInfo, EnumInfo, FunctionInfo, PropertyInfo, StructInfo};
7
8pub struct CodegenContext {
10 pub classes: HashMap<String, ClassInfo>,
12 pub structs: HashMap<String, StructInfo>,
14 pub enums: HashMap<String, EnumInfo>,
16
17 pub package_to_module: HashMap<String, String>,
19 pub module_to_feature: HashMap<String, String>,
21 pub enabled_modules: HashSet<String>,
23
24 pub module_classes: BTreeMap<String, Vec<ClassInfo>>,
26 pub module_structs: BTreeMap<String, Vec<StructInfo>>,
28 pub module_enums: BTreeMap<String, Vec<EnumInfo>>,
30
31 pub func_table: Vec<FuncEntry>,
33
34 pub module_deps: BTreeMap<String, std::collections::BTreeSet<String>>,
37}
38
39#[derive(Clone)]
41pub struct FuncEntry {
42 pub func_id: u32,
43 pub module_name: String,
44 pub class_name: String,
45 pub func_name: String,
46 pub rust_func_name: String,
48 pub func: FunctionInfo,
49 pub cpp_class_name: String,
51 pub header: String,
53}
54
55impl CodegenContext {
56 pub fn new(
57 classes: Vec<ClassInfo>,
58 structs: Vec<StructInfo>,
59 enums: Vec<EnumInfo>,
60 config: &CodegenConfig,
61 ) -> Self {
62 let mut package_to_module = HashMap::new();
64 let mut module_to_feature_map = HashMap::new();
65
66 for (pkg, mapping) in &config.modules {
67 package_to_module.insert(pkg.clone(), mapping.module.clone());
68 module_to_feature_map.insert(mapping.module.clone(), mapping.feature.clone());
69 }
70
71 let enabled_features: HashSet<&str> = config.features.iter().map(|s| s.as_str()).collect();
73 let mut enabled_modules = HashSet::new();
74 for (pkg, mapping) in &config.modules {
75 if enabled_features.contains(mapping.feature.as_str()) {
76 enabled_modules.insert(mapping.module.clone());
77 package_to_module.entry(pkg.clone()).or_insert_with(|| mapping.module.clone());
79 }
80 }
81
82 let mut all_packages = HashSet::new();
84 for c in &classes {
85 all_packages.insert(c.package.clone());
86 }
87 for s in &structs {
88 all_packages.insert(s.package.clone());
89 }
90 for e in &enums {
91 all_packages.insert(e.package.clone());
92 }
93
94 for pkg in &all_packages {
95 if !package_to_module.contains_key(pkg) {
96 let module = crate::naming::to_snake_case(pkg);
97 package_to_module.insert(pkg.clone(), module);
98 }
99 }
100
101 let mut module_classes: BTreeMap<String, Vec<ClassInfo>> = BTreeMap::new();
103 let mut module_structs: BTreeMap<String, Vec<StructInfo>> = BTreeMap::new();
104 let mut module_enums: BTreeMap<String, Vec<EnumInfo>> = BTreeMap::new();
105
106 let mut classes_map = HashMap::new();
107 for c in classes {
108 if let Some(module) = package_to_module.get(&c.package)
109 && enabled_modules.contains(module)
110 {
111 classes_map.insert(c.name.clone(), c.clone());
112 module_classes.entry(module.clone()).or_default().push(c);
113 }
114 }
115
116 let mut structs_map = HashMap::new();
117 for s in structs {
118 if let Some(module) = package_to_module.get(&s.package)
119 && enabled_modules.contains(module)
120 {
121 structs_map.insert(s.name.clone(), s.clone());
122 module_structs.entry(module.clone()).or_default().push(s);
123 }
124 }
125
126 let mut enums_map = HashMap::new();
127 for e in enums {
128 if let Some(module) = package_to_module.get(&e.package)
129 && enabled_modules.contains(module)
130 {
131 enums_map.insert(e.name.clone(), e.clone());
132 module_enums.entry(module.clone()).or_default().push(e);
133 }
134 }
135
136 for classes in module_classes.values_mut() {
138 classes.sort_by(|a, b| a.name.cmp(&b.name));
139 }
140 for structs in module_structs.values_mut() {
141 structs.sort_by(|a, b| a.name.cmp(&b.name));
142 }
143 for enums in module_enums.values_mut() {
144 enums.sort_by(|a, b| a.name.cmp(&b.name));
145 }
146
147 let mut ctx = CodegenContext {
148 classes: classes_map,
149 structs: structs_map,
150 enums: enums_map,
151 package_to_module,
152 module_to_feature: module_to_feature_map,
153 enabled_modules,
154 module_classes,
155 module_structs,
156 module_enums,
157 func_table: Vec::new(),
158 module_deps: BTreeMap::new(),
159 };
160 ctx.module_deps = ctx.compute_module_deps();
161 ctx
162 }
163
164 fn compute_module_deps(&self) -> BTreeMap<String, std::collections::BTreeSet<String>> {
171 let mut deps: BTreeMap<String, std::collections::BTreeSet<String>> = BTreeMap::new();
172 for m in &self.enabled_modules {
173 deps.entry(m.clone()).or_default();
174 }
175
176 for (module, classes) in &self.module_classes {
177 for class in classes {
178 if let Some(parent) = &class.super_class
179 && let Some(pc) = self.classes.get(parent.as_str())
180 {
181 self.record_dep(module, &pc.package, &mut deps);
182 }
183 for iface in &class.interfaces {
184 if let Some(ic) = self.classes.get(iface.as_str()) {
185 self.record_dep(module, &ic.package, &mut deps);
186 }
187 }
188 for prop in &class.props {
189 self.walk_prop_deps(prop, module, &mut deps);
190 }
191 for func in &class.funcs {
192 for p in &func.params {
193 self.walk_param_deps(p, module, &mut deps);
194 }
195 }
196 }
197 }
198
199 for (module, structs) in &self.module_structs {
200 for s in structs {
201 if let Some(parent) = &s.super_struct
202 && let Some(ps) = self.structs.get(parent.as_str())
203 {
204 self.record_dep(module, &ps.package, &mut deps);
205 }
206 for prop in &s.props {
207 self.walk_prop_deps(prop, module, &mut deps);
208 }
209 }
210 }
211
212 deps
213 }
214
215 fn record_dep(
216 &self,
217 current_module: &str,
218 target_package: &str,
219 deps: &mut BTreeMap<String, std::collections::BTreeSet<String>>,
220 ) {
221 if let Some(target_module) = self.package_to_module.get(target_package)
222 && target_module != current_module && self.enabled_modules.contains(target_module)
223 {
224 deps.entry(current_module.to_string())
225 .or_default()
226 .insert(target_module.clone());
227 }
228 }
229
230 fn walk_prop_deps(
231 &self,
232 prop: &PropertyInfo,
233 current_module: &str,
234 deps: &mut BTreeMap<String, std::collections::BTreeSet<String>>,
235 ) {
236 if let Some(en) = &prop.enum_name
237 && let Some(e) = self.enums.get(en.as_str())
238 {
239 self.record_dep(current_module, &e.package, deps);
240 }
241 if let Some(cn) = &prop.class_name
242 && let Some(c) = self.classes.get(cn.as_str())
243 {
244 self.record_dep(current_module, &c.package, deps);
245 }
246 if let Some(mc) = &prop.meta_class_name
247 && let Some(c) = self.classes.get(mc.as_str())
248 {
249 self.record_dep(current_module, &c.package, deps);
250 }
251 if let Some(sn) = &prop.struct_name
252 && let Some(s) = self.structs.get(sn.as_str())
253 {
254 self.record_dep(current_module, &s.package, deps);
255 }
256 if let Some(in_) = &prop.interface_name
257 && let Some(c) = self.classes.get(in_.as_str())
258 {
259 self.record_dep(current_module, &c.package, deps);
260 }
261 if let Some(fi) = &prop.func_info {
262 self.walk_delegate_func_info_deps(fi, current_module, deps);
263 }
264 if let Some(inner) = &prop.inner_prop {
265 self.walk_prop_deps(inner, current_module, deps);
266 }
267 if let Some(key) = &prop.key_prop {
268 self.walk_prop_deps(key, current_module, deps);
269 }
270 if let Some(value) = &prop.value_prop {
271 self.walk_prop_deps(value, current_module, deps);
272 }
273 if let Some(element) = &prop.element_prop {
274 self.walk_prop_deps(element, current_module, deps);
275 }
276 }
277
278 fn walk_param_deps(
279 &self,
280 param: &crate::schema::ParamInfo,
281 current_module: &str,
282 deps: &mut BTreeMap<String, std::collections::BTreeSet<String>>,
283 ) {
284 if let Some(en) = ¶m.enum_name
285 && let Some(e) = self.enums.get(en.as_str())
286 {
287 self.record_dep(current_module, &e.package, deps);
288 }
289 if let Some(cn) = ¶m.class_name
290 && let Some(c) = self.classes.get(cn.as_str())
291 {
292 self.record_dep(current_module, &c.package, deps);
293 }
294 if let Some(mc) = ¶m.meta_class_name
295 && let Some(c) = self.classes.get(mc.as_str())
296 {
297 self.record_dep(current_module, &c.package, deps);
298 }
299 if let Some(sn) = ¶m.struct_name
300 && let Some(s) = self.structs.get(sn.as_str())
301 {
302 self.record_dep(current_module, &s.package, deps);
303 }
304 if let Some(in_) = ¶m.interface_name
305 && let Some(c) = self.classes.get(in_.as_str())
306 {
307 self.record_dep(current_module, &c.package, deps);
308 }
309 if let Some(inner) = ¶m.inner_prop {
310 self.walk_prop_deps(inner, current_module, deps);
311 }
312 if let Some(key) = ¶m.key_prop {
313 self.walk_prop_deps(key, current_module, deps);
314 }
315 if let Some(value) = ¶m.value_prop {
316 self.walk_prop_deps(value, current_module, deps);
317 }
318 if let Some(element) = ¶m.element_prop {
319 self.walk_prop_deps(element, current_module, deps);
320 }
321 }
322
323 fn walk_delegate_func_info_deps(
324 &self,
325 fi: &serde_json::Value,
326 current_module: &str,
327 deps: &mut BTreeMap<String, std::collections::BTreeSet<String>>,
328 ) {
329 let Some(params) = fi.get("params").and_then(|p| p.as_array()) else { return };
330 for p in params {
331 if let Some(en) = p.get("enum_name").and_then(|v| v.as_str())
332 && let Some(e) = self.enums.get(en)
333 {
334 self.record_dep(current_module, &e.package, deps);
335 }
336 if let Some(cn) = p.get("class_name").and_then(|v| v.as_str())
337 && let Some(c) = self.classes.get(cn)
338 {
339 self.record_dep(current_module, &c.package, deps);
340 }
341 if let Some(mc) = p.get("meta_class_name").and_then(|v| v.as_str())
342 && let Some(c) = self.classes.get(mc)
343 {
344 self.record_dep(current_module, &c.package, deps);
345 }
346 if let Some(sn) = p.get("struct_name").and_then(|v| v.as_str())
347 && let Some(s) = self.structs.get(sn)
348 {
349 self.record_dep(current_module, &s.package, deps);
350 }
351 if let Some(in_) = p.get("interface_name").and_then(|v| v.as_str())
352 && let Some(c) = self.classes.get(in_)
353 {
354 self.record_dep(current_module, &c.package, deps);
355 }
356 }
357 }
358
359 #[allow(dead_code)]
361 pub fn is_type_available(&self, type_name: &str) -> bool {
362 self.classes.contains_key(type_name)
363 || self.structs.contains_key(type_name)
364 || self.enums.contains_key(type_name)
365 }
366
367 #[allow(dead_code)]
369 pub fn module_for_package(&self, package: &str) -> Option<&str> {
370 self.package_to_module.get(package).map(|s| s.as_str())
371 }
372
373 pub fn feature_for_module(&self, module: &str) -> Option<&str> {
375 self.module_to_feature.get(module).map(|s| s.as_str())
376 }
377
378 pub fn enum_actual_repr(&self, enum_name: &str) -> Option<&'static str> {
381 let e = self.enums.get(enum_name)?;
382 let has_negative = e.pairs.iter().any(|(_, v)| *v < 0);
383 Some(if has_negative {
384 match e.underlying_type.as_str() {
385 "uint8" => "i8",
386 "int8" => "i8",
387 "uint16" => "i16",
388 "int16" => "i16",
389 "uint32" => "i32",
390 "int32" => "i32",
391 "uint64" => "i64",
392 "int64" => "i64",
393 _ => "i8",
394 }
395 } else {
396 match e.underlying_type.as_str() {
397 "uint8" => "u8",
398 "int8" => "i8",
399 "uint16" => "u16",
400 "int16" => "i16",
401 "uint32" => "u32",
402 "int32" => "i32",
403 "uint64" => "u64",
404 "int64" => "i64",
405 _ => "u8",
406 }
407 })
408 }
409}