1use super::*;
2
3#[derive(Default)]
5pub struct Remapper {
6 input: Vec<PathBuf>,
7 output: PathBuf,
8 routes: HashMap<String, String>,
9 sources: Vec<String>,
10 fallback: String,
11}
12
13impl Remapper {
14 pub fn new() -> Self {
15 Self::default()
16 }
17
18 pub fn input(&mut self, input: impl AsRef<Path>) -> &mut Self {
19 self.input.push(input.as_ref().to_path_buf());
20 self
21 }
22
23 pub fn inputs<I, S>(&mut self, inputs: I) -> &mut Self
24 where
25 I: IntoIterator<Item = S>,
26 S: AsRef<Path>,
27 {
28 for input in inputs {
29 self.input(input);
30 }
31 self
32 }
33
34 pub fn source(&mut self, namespace: &str) -> &mut Self {
36 self.sources.push(namespace.to_string());
37 self
38 }
39
40 pub fn sources<I, S>(&mut self, namespaces: I) -> &mut Self
42 where
43 I: IntoIterator<Item = S>,
44 S: AsRef<str>,
45 {
46 for namespace in namespaces {
47 self.source(namespace.as_ref());
48 }
49 self
50 }
51
52 pub fn fallback(&mut self, namespace: &str) -> &mut Self {
53 self.fallback = namespace.to_string();
54 self
55 }
56
57 pub fn route(&mut self, name: impl Into<String>, namespace: impl Into<String>) -> &mut Self {
58 self.routes.insert(name.into(), namespace.into());
59 self
60 }
61
62 pub fn routes<I, K, V>(&mut self, routes: I) -> &mut Self
63 where
64 I: IntoIterator<Item = (K, V)>,
65 K: Into<String>,
66 V: Into<String>,
67 {
68 for (name, namespace) in routes {
69 self.route(name, namespace);
70 }
71 self
72 }
73
74 pub fn output(&mut self, output: impl AsRef<Path>) -> &mut Self {
75 self.output = output.as_ref().to_path_buf();
76 self
77 }
78
79 pub fn remap(&self) -> Result<(), Error> {
80 if self.output.as_os_str().is_empty() {
81 return Err(Error::new("output is required"));
82 }
83
84 let name = self
85 .output
86 .file_stem()
87 .and_then(|s| s.to_str())
88 .ok_or_else(|| {
89 Error::new(format!("invalid output path `{}`", self.output.display()))
90 })?;
91
92 let files = read_inputs(&self.input)?;
93 let index = reader::Index::new(files);
94 let mut file = writer::File::new(name);
95
96 let mut apis: Vec<reader::TypeDef> = Vec::new();
98 let mut types: Vec<reader::TypeDef> = index.types().collect();
99 types.sort_by(|a, b| (a.namespace(), a.name()).cmp(&(b.namespace(), b.name())));
100
101 for ty in types {
102 if self.is_source_apis(ty) {
103 apis.push(ty);
104 } else {
105 self.write_type(&mut file, &index, ty, None);
106 }
107 }
108
109 self.split_apis(&mut file, &apis);
110
111 let bytes = file.into_stream();
112 std::fs::write(&self.output, bytes)
113 .map_err(|e| Error::new(format!("failed to write `{}`: {e}", self.output.display())))
114 }
115
116 fn is_source_apis(&self, ty: reader::TypeDef) -> bool {
117 !ty.flags().contains(TypeAttributes::WindowsRuntime)
118 && ty.category() == reader::TypeCategory::Class
119 && ty.name() == "Apis"
120 && self.sources.iter().any(|s| s == ty.namespace())
121 }
122
123 fn target(&self, namespace: &str, name: &str) -> String {
124 if self.sources.iter().any(|s| s == namespace) {
125 self.routes
126 .get(trim_tick(name))
127 .cloned()
128 .unwrap_or_else(|| self.fallback.clone())
129 } else {
130 namespace.to_string()
131 }
132 }
133
134 fn remap_type(&self, ty: &Type) -> Type {
135 match ty {
136 Type::ClassName(tn) => Type::ClassName(self.remap_type_name(tn)),
137 Type::ValueName(tn) => Type::ValueName(self.remap_type_name(tn)),
138 Type::Array(inner) => Type::Array(Box::new(self.remap_type(inner))),
139 Type::RefMut(inner) => Type::RefMut(Box::new(self.remap_type(inner))),
140 Type::RefConst(inner) => Type::RefConst(Box::new(self.remap_type(inner))),
141 Type::PtrMut(inner, n) => Type::PtrMut(Box::new(self.remap_type(inner)), *n),
142 Type::PtrConst(inner, n) => Type::PtrConst(Box::new(self.remap_type(inner)), *n),
143 Type::ArrayFixed(inner, n) => Type::ArrayFixed(Box::new(self.remap_type(inner)), *n),
144 other => other.clone(),
145 }
146 }
147
148 fn remap_type_name(&self, tn: &TypeName) -> TypeName {
149 TypeName {
150 namespace: self.target(&tn.namespace, &tn.name),
151 name: tn.name.clone(),
152 generics: tn.generics.iter().map(|g| self.remap_type(g)).collect(),
153 }
154 }
155
156 fn remap_signature(&self, sig: &Signature) -> Signature {
157 Signature {
158 flags: sig.flags,
159 return_type: self.remap_type(&sig.return_type),
160 types: sig.types.iter().map(|t| self.remap_type(t)).collect(),
161 }
162 }
163
164 fn remap_extends(&self, file: &mut writer::File, def: reader::TypeDef) -> writer::TypeDefOrRef {
165 def.extends()
166 .map(|extends| {
167 let namespace = self.target(extends.namespace(), extends.name());
168 writer::TypeDefOrRef::TypeRef(file.TypeRef(&namespace, extends.name()))
169 })
170 .unwrap_or_default()
171 }
172
173 fn write_type(
175 &self,
176 file: &mut writer::File,
177 index: &reader::Index,
178 def: reader::TypeDef,
179 outer: Option<writer::TypeDef>,
180 ) {
181 let extends = self.remap_extends(file, def);
182 let namespace = if def.flags().is_nested() {
183 String::new()
184 } else {
185 self.target(def.namespace(), def.name())
186 };
187
188 let type_def = file.TypeDef(&namespace, def.name(), extends, def.flags());
189
190 if let Some(outer) = outer {
191 file.NestedClass(type_def, outer);
192 }
193
194 for field in def.fields() {
195 let field_def = file.Field(field.name(), &self.remap_type(&field.ty()), field.flags());
196 if let Some(constant) = field.constant() {
197 file.Constant(writer::HasConstant::Field(field_def), &constant.value());
198 }
199 write_attributes(file, writer::HasAttribute::Field(field_def), field);
200 }
201
202 let generics: Vec<_> = def
203 .generic_params()
204 .map(|param| Type::Generic(param.name().to_string(), param.sequence()))
205 .collect();
206
207 write_attributes(file, writer::HasAttribute::TypeDef(type_def), def);
208
209 for map in def.interface_impls() {
210 let interface = self.remap_type(&map.interface(&generics));
211 let interface_impl = file.InterfaceImpl(type_def, &interface);
212 write_attributes(
213 file,
214 writer::HasAttribute::InterfaceImpl(interface_impl),
215 map,
216 );
217 }
218
219 for generic in def.generic_params() {
220 file.GenericParam(
221 generic.name(),
222 writer::TypeOrMethodDef::TypeDef(type_def),
223 generic.sequence(),
224 generic.flags(),
225 );
226 }
227
228 let is_winrt_class = def.category() == reader::TypeCategory::Class
229 && def.flags().contains(TypeAttributes::WindowsRuntime);
230
231 if !is_winrt_class {
232 for method in def.methods() {
233 self.write_method(file, method, &generics);
234 }
235 }
236
237 if let Some(class_layout) = def.class_layout() {
238 file.ClassLayout(
239 type_def,
240 class_layout.packing_size(),
241 class_layout.class_size(),
242 );
243 }
244
245 for inner_def in index.nested(def) {
246 self.write_type(file, index, inner_def, Some(type_def));
247 }
248 }
249
250 fn write_method(&self, file: &mut writer::File, method: reader::MethodDef, generics: &[Type]) {
251 let signature = self.remap_signature(&method.signature(generics));
252 let method_def = file.MethodDef(
253 method.name(),
254 &signature,
255 method.flags(),
256 method.impl_flags(),
257 );
258 for param_def in method.params() {
259 let param = file.Param(param_def.name(), param_def.sequence(), param_def.flags());
260 write_attributes(file, writer::HasAttribute::Param(param), param_def);
261 }
262 write_attributes(file, writer::HasAttribute::MethodDef(method_def), method);
263 if let Some(impl_map) = method.impl_map() {
264 file.ImplMap(
265 method_def,
266 impl_map.flags(),
267 impl_map.import_name(),
268 impl_map.import_scope().name(),
269 );
270 }
271 }
272
273 fn split_apis(&self, file: &mut writer::File, apis: &[reader::TypeDef]) {
275 let mut namespaces: Vec<String> = Vec::new();
276 let mut fields: HashMap<String, Vec<reader::Field>> = HashMap::new();
277 let mut methods: HashMap<String, Vec<reader::MethodDef>> = HashMap::new();
278
279 let record = |namespaces: &mut Vec<String>, namespace: String| {
280 if !namespaces.contains(&namespace) {
281 namespaces.push(namespace);
282 }
283 };
284
285 let template = apis.first().copied();
286
287 for &container in apis {
288 for field in container.fields() {
289 let namespace = self.target(container.namespace(), field.name());
290 record(&mut namespaces, namespace.clone());
291 fields.entry(namespace).or_default().push(field);
292 }
293 for method in container.methods() {
294 let namespace = self.target(container.namespace(), method.name());
295 record(&mut namespaces, namespace.clone());
296 methods.entry(namespace).or_default().push(method);
297 }
298 }
299
300 namespaces.sort();
301
302 let Some(template) = template else { return };
303
304 for namespace in &namespaces {
305 let extends = self.remap_extends(file, template);
306 let type_def = file.TypeDef(namespace, "Apis", extends, template.flags());
307
308 for field in fields.get(namespace).into_iter().flatten() {
309 let field_def =
310 file.Field(field.name(), &self.remap_type(&field.ty()), field.flags());
311 if let Some(constant) = field.constant() {
312 file.Constant(writer::HasConstant::Field(field_def), &constant.value());
313 }
314 write_attributes(file, writer::HasAttribute::Field(field_def), *field);
315 }
316
317 for method in methods.get(namespace).into_iter().flatten() {
318 self.write_method(file, *method, &[]);
319 }
320
321 write_attributes(file, writer::HasAttribute::TypeDef(type_def), template);
322 }
323 }
324}