1use std::collections::{BTreeMap, HashMap, HashSet};
4
5use crate::config::CodegenConfig;
6use crate::schema::{ClassInfo, EnumInfo, FunctionInfo, 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
35#[derive(Clone)]
37pub struct FuncEntry {
38 pub func_id: u32,
39 pub module_name: String,
40 pub class_name: String,
41 pub func_name: String,
42 pub rust_func_name: String,
44 pub func: FunctionInfo,
45 pub cpp_class_name: String,
47 pub header: String,
49}
50
51impl CodegenContext {
52 pub fn new(
53 classes: Vec<ClassInfo>,
54 structs: Vec<StructInfo>,
55 enums: Vec<EnumInfo>,
56 config: &CodegenConfig,
57 ) -> Self {
58 let mut package_to_module = HashMap::new();
60 let mut module_to_feature_map = HashMap::new();
61
62 for (pkg, mapping) in &config.modules {
63 package_to_module.insert(pkg.clone(), mapping.module.clone());
64 module_to_feature_map.insert(mapping.module.clone(), mapping.feature.clone());
65 }
66
67 let enabled_features: HashSet<&str> = config.features.iter().map(|s| s.as_str()).collect();
69 let mut enabled_modules = HashSet::new();
70 for (pkg, mapping) in &config.modules {
71 if enabled_features.contains(mapping.feature.as_str()) {
72 enabled_modules.insert(mapping.module.clone());
73 package_to_module.entry(pkg.clone()).or_insert_with(|| mapping.module.clone());
75 }
76 }
77
78 let mut all_packages = HashSet::new();
80 for c in &classes {
81 all_packages.insert(c.package.clone());
82 }
83 for s in &structs {
84 all_packages.insert(s.package.clone());
85 }
86 for e in &enums {
87 all_packages.insert(e.package.clone());
88 }
89
90 for pkg in &all_packages {
91 if !package_to_module.contains_key(pkg) {
92 let module = crate::naming::to_snake_case(pkg);
93 package_to_module.insert(pkg.clone(), module);
94 }
95 }
96
97 let mut module_classes: BTreeMap<String, Vec<ClassInfo>> = BTreeMap::new();
99 let mut module_structs: BTreeMap<String, Vec<StructInfo>> = BTreeMap::new();
100 let mut module_enums: BTreeMap<String, Vec<EnumInfo>> = BTreeMap::new();
101
102 let mut classes_map = HashMap::new();
103 for c in classes {
104 if let Some(module) = package_to_module.get(&c.package) {
105 if enabled_modules.contains(module) {
106 classes_map.insert(c.name.clone(), c.clone());
107 module_classes.entry(module.clone()).or_default().push(c);
108 }
109 }
110 }
111
112 let mut structs_map = HashMap::new();
113 for s in structs {
114 if let Some(module) = package_to_module.get(&s.package) {
115 if enabled_modules.contains(module) {
116 structs_map.insert(s.name.clone(), s.clone());
117 module_structs.entry(module.clone()).or_default().push(s);
118 }
119 }
120 }
121
122 let mut enums_map = HashMap::new();
123 for e in enums {
124 if let Some(module) = package_to_module.get(&e.package) {
125 if enabled_modules.contains(module) {
126 enums_map.insert(e.name.clone(), e.clone());
127 module_enums.entry(module.clone()).or_default().push(e);
128 }
129 }
130 }
131
132 for classes in module_classes.values_mut() {
134 classes.sort_by(|a, b| a.name.cmp(&b.name));
135 }
136 for structs in module_structs.values_mut() {
137 structs.sort_by(|a, b| a.name.cmp(&b.name));
138 }
139 for enums in module_enums.values_mut() {
140 enums.sort_by(|a, b| a.name.cmp(&b.name));
141 }
142
143 CodegenContext {
144 classes: classes_map,
145 structs: structs_map,
146 enums: enums_map,
147 package_to_module,
148 module_to_feature: module_to_feature_map,
149 enabled_modules,
150 module_classes,
151 module_structs,
152 module_enums,
153 func_table: Vec::new(),
154 }
155 }
156
157 #[allow(dead_code)]
159 pub fn is_type_available(&self, type_name: &str) -> bool {
160 self.classes.contains_key(type_name)
161 || self.structs.contains_key(type_name)
162 || self.enums.contains_key(type_name)
163 }
164
165 #[allow(dead_code)]
167 pub fn module_for_package(&self, package: &str) -> Option<&str> {
168 self.package_to_module.get(package).map(|s| s.as_str())
169 }
170
171 pub fn feature_for_module(&self, module: &str) -> Option<&str> {
173 self.module_to_feature.get(module).map(|s| s.as_str())
174 }
175
176 pub fn enum_actual_repr(&self, enum_name: &str) -> Option<&'static str> {
179 let e = self.enums.get(enum_name)?;
180 let has_negative = e.pairs.iter().any(|(_, v)| *v < 0);
181 Some(if has_negative {
182 match e.underlying_type.as_str() {
183 "uint8" => "i8",
184 "int8" => "i8",
185 "uint16" => "i16",
186 "int16" => "i16",
187 "uint32" => "i32",
188 "int32" => "i32",
189 "uint64" => "i64",
190 "int64" => "i64",
191 _ => "i8",
192 }
193 } else {
194 match e.underlying_type.as_str() {
195 "uint8" => "u8",
196 "int8" => "i8",
197 "uint16" => "u16",
198 "int16" => "i16",
199 "uint32" => "u32",
200 "int32" => "i32",
201 "uint64" => "u64",
202 "int64" => "i64",
203 _ => "u8",
204 }
205 })
206 }
207}