1use std::fmt::Display;
2use std::io;
3use std::io::Write;
4use std::path::Path;
5
6use indoc::indoc;
7use uuid::Uuid;
8
9use crate::codegen::{Ctype, File, Function, Interface, InterfaceDefn, Toplevel};
10
11pub fn write_cguid<W: Write>(mut w: W, f: &File, source: &Path) -> io::Result<()> {
12 writeln!(w, "// Auto-generated by nuidl from {}.", source.display())?;
13 writeln!(w, "#include <nucom/idldefs.h>")?;
14 writeln!(w)?;
15
16 for el in &f.elems {
17 if let Toplevel::Interface(itf) = el {
18 if let Some(InterfaceDefn {
19 uuid: Some(uuid), ..
20 }) = itf.defn
21 {
22 writeln!(w, "const GUID IID_{} = {};", itf.name, GuidRepr(uuid))?;
23 }
24 }
25 }
26
27 Ok(())
28}
29
30pub fn write_header<W: Write>(
31 mut w: W,
32 f: &File,
33 source: &Path,
34 guard_name: &str,
35) -> io::Result<()> {
36 writeln!(
37 w,
38 indoc! {r#"
39 // Auto-generated by nuidl from {}.
40 #ifndef {1}
41 #define {1}
42
43 #include <nucom/idldefs.h>
44 "#},
45 source.display(),
46 guard_name,
47 )?;
48
49 for el in &f.imports {
50 writeln!(w, "#include \"{}\"", el.c_name.display())?;
51 }
52
53 for el in &f.elems {
54 if let Toplevel::Interface(itf) = el {
55 writeln!(w, "typedef struct {0} {0};", itf.name)?;
56 }
57 }
58
59 for el in &f.elems {
60 match el {
61 Toplevel::CppQuote(text) => {
62 writeln!(w, "{}", text)?;
63 }
64 Toplevel::Interface(i) => {
65 print_interface(&mut w, i)?;
66 }
67 }
68 }
69
70 writeln!(
71 w,
72 indoc! {r#"
73 #endif // {}
74 "#},
75 guard_name
76 )?;
77
78 Ok(())
79}
80
81fn write_type_space<W: Write>(t: &Ctype, mut w: W, with_space: bool) -> io::Result<()> {
82 write!(w, "{}", t.typename)?;
83
84 if t.is_const {
85 write!(w, " const")?;
86 }
87
88 let mut next_space = true;
89
90 for ptr in &t.indirection {
91 if next_space {
92 write!(w, " ")?;
93 }
94
95 write!(w, "*")?;
96
97 if ptr.is_const {
98 write!(w, "const")?;
99 }
100
101 next_space = ptr.is_const;
102 }
103
104 if next_space && with_space {
105 write!(w, " ")?;
106 }
107
108 Ok(())
109}
110
111fn write_type<W: Write>(t: &Ctype, w: W) -> io::Result<()> {
112 write_type_space(t, w, true)
113}
114
115struct GuidRepr(Uuid);
116
117impl Display for GuidRepr {
118 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
119 let (d1, d2, d3, d4) = self.0.as_fields();
120
121 write!(f, "{{0x{:X},", d1)?;
122 write!(f, "0x{:X},", d2)?;
123 write!(f, "0x{:X},{{", d3)?;
124
125 for el in d4 {
126 write!(f, "0x{:X},", el)?;
127 }
128
129 write!(f, "}}}}")?;
130
131 Ok(())
132 }
133}
134
135fn print_interface<W: Write>(w: &mut W, i: &Interface) -> io::Result<()> {
136 if i.defn.is_none() {
137 return Ok(());
138 }
139
140 writeln!(
141 w,
142 indoc! {r#"
143
144 // interface {}
145
146 #if !defined(__cplusplus) || defined(CINTERFACE)
147
148 #if defined(__cplusplus)
149 extern "C" {{
150 #endif
151 "#},
152 i.name
153 )?;
154
155 print_c_interface(&mut *w, i)?;
156
157 writeln!(
158 w,
159 indoc! {r#"
160 #if defined(__cplusplus)
161 }}
162 #endif
163
164 #else
165 "#}
166 )?;
167
168 print_cpp_interface(&mut *w, i)?;
169
170 writeln!(
171 w,
172 indoc! {r#"
173 #endif
174 "#}
175 )?;
176
177 Ok(())
178}
179
180fn print_c_interface<W: Write>(w: &mut W, i: &Interface) -> io::Result<()> {
181 let defn = i.defn.as_ref().unwrap();
182
183 writeln!(w, "struct {}Vtbl\n{{\n BEGIN_INTERFACE", i.name)?;
184 writeln!(w)?;
185
186 print_c_functions(&mut *w, i, i)?;
187
188 writeln!(w, " END_INTERFACE\n}};")?;
189 writeln!(
190 w,
191 "struct {0}\n{{\n struct {0}Vtbl *lpVtbl;\n}};",
192 i.name
193 )?;
194
195 writeln!(w)?;
196
197 if defn.uuid.is_some() {
198 writeln!(w, "extern IID const IID_{};", i.name)?;
199 writeln!(w)?;
200 }
201
202 print_c_call_macros(&mut *w, i, i)?;
203
204 Ok(())
205}
206
207fn print_c_functions<W: Write>(w: &mut W, i: &Interface, cur: &Interface) -> io::Result<()> {
208 let cur_defn = cur.defn.as_ref().unwrap();
209
210 if let Some(base) = &cur_defn.base {
211 print_c_functions(&mut *w, i, base)?;
212 }
213
214 writeln!(w, " // {}\n", cur.name)?;
215
216 for f in &cur_defn.fns {
217 print_c_function(&mut *w, i, &f)?;
218 writeln!(w)?;
219 }
220
221 Ok(())
222}
223
224fn print_c_function<W: Write>(w: &mut W, i: &Interface, f: &Function) -> io::Result<()> {
225 write!(w, " ")?;
226 write_type(&f.ret, &mut *w)?;
227 write!(
228 w,
229 "(STDMETHODCALLTYPE *{})(\n {} *self",
230 f.name, i.name
231 )?;
232
233 for arg in &f.params {
234 write!(w, ",\n ")?;
235 write_type(&arg.ty, &mut *w)?;
236
237 if let Some(name) = &arg.name {
238 write!(w, "{}", **name)?;
239 }
240 }
241
242 writeln!(w, "\n );")?;
243 Ok(())
244}
245
246fn print_c_call_macros<W: Write>(w: &mut W, i: &Interface, cur: &Interface) -> io::Result<()> {
247 let cur_defn = cur.defn.as_ref().unwrap();
248
249 if let Some(base) = &cur_defn.base {
250 print_c_call_macros(&mut *w, i, base)?;
251 }
252
253 for f in &cur_defn.fns {
254 print_c_call_macro(&mut *w, i, &f)?;
255 }
256
257 Ok(())
258}
259
260fn print_c_call_macro<W: Write>(w: &mut W, i: &Interface, f: &Function) -> io::Result<()> {
261 write!(w, "#define {}_{}(self", i.name, f.name)?;
262
263 let write_params_block = |w: &mut W| {
264 for (idx, arg) in f.params.iter().enumerate() {
265 write!(w, ", ")?;
266
267 match &arg.name {
268 Some(name) => write!(w, "{}", **name)?,
269 _ => write!(w, "p{}", idx)?,
270 }
271 }
272
273 Ok::<(), io::Error>(())
274 };
275
276 write_params_block(&mut *w)?;
277
278 write!(w, ") (self->lpVtbl->{}(self", f.name)?;
279
280 write_params_block(&mut *w)?;
281
282 writeln!(w, "))")?;
283
284 Ok(())
285}
286
287fn print_cpp_interface<W: Write>(w: &mut W, i: &Interface) -> io::Result<()> {
288 let defn = i.defn.as_ref().unwrap();
289
290 write!(w, "struct {}", i.name)?;
291
292 if let Some(n) = &defn.base {
293 write!(w, " : public {}", n.name)?;
294 };
295
296 writeln!(w, "\n{{\n BEGIN_INTERFACE")?;
297 writeln!(w)?;
298
299 print_cpp_functions(&mut *w, i)?;
300
301 writeln!(w, " END_INTERFACE\n}};")?;
302 writeln!(w)?;
303
304 if let Some(guid) = defn.uuid {
305 write!(
306 w,
307 indoc! {r#"
308 extern "C" IID const IID_{};
309
310 namespace nucom {{
311
312 extern "C++" template<>
313 struct GuidOf<{0}>
314 {{
315 static constexpr GUID guid = {};
316 }};
317
318 }}
319
320 "#},
321 i.name,
322 GuidRepr(guid)
323 )?;
324 }
325
326 Ok(())
327}
328
329fn print_cpp_functions<W: Write>(w: &mut W, i: &Interface) -> io::Result<()> {
330 let InterfaceDefn { base, fns, .. } = i.defn.as_ref().unwrap();
331
332 let mut base = base;
333 let mut needs_space = false;
334
335 while let Some(Interface {
336 name: base_name,
337 defn:
338 Some(InterfaceDefn {
339 fns: base_fns,
340 base: base_base,
341 ..
342 }),
343 ..
344 }) = base.as_deref()
345 {
346 for f in base_fns {
347 if f.params.iter().any(|p| p.poly_type.is_some()) {
348 writeln!(w, " using {}::{};", base_name, f.name)?;
349 needs_space = true;
350 }
351 }
352
353 base = &base_base;
354 }
355
356 if needs_space {
357 writeln!(w)?;
358 }
359
360 for f in fns {
361 print_cpp_function(&mut *w, i, &f)?;
362 writeln!(w)?;
363 }
364
365 Ok(())
366}
367
368fn print_cpp_function<W: Write>(w: &mut W, _i: &Interface, f: &Function) -> io::Result<()> {
369 write!(w, " virtual ")?;
370 write_type(&f.ret, &mut *w)?;
371 write!(w, "STDMETHODCALLTYPE {}(", f.name)?;
372
373 for (idx, arg) in f.params.iter().enumerate() {
374 if idx > 0 {
375 write!(w, ",")?;
376 }
377
378 write!(w, "\n ")?;
379
380 write_type(&arg.ty, &mut *w)?;
381
382 if let Some(name) = &arg.name {
383 write!(w, "{}", **name)?;
384 }
385 }
386
387 if !f.params.is_empty() {
388 write!(w, "\n ")?;
389 }
390
391 writeln!(w, ") = 0;")?;
392
393 if f.params.iter().any(|p| p.poly_type.is_some()) {
396 writeln!(w)?;
397
398 #[derive(Debug)]
399 struct PolyTypeInfo {
400 value_pos: usize,
401 template_idx: usize,
402 }
403
404 let mut poly_types = Vec::new();
405 let mut type_idx = 1;
406
407 for (idx, param) in f.params.iter().enumerate() {
408 if let Some(_pt) = ¶m.poly_type {
409 poly_types.push(PolyTypeInfo {
410 value_pos: idx,
411 template_idx: type_idx,
412 });
413
414 type_idx += 1;
415 }
416 }
417
418 write!(w, " template <")?;
419
420 for (idx, pt) in poly_types.iter().enumerate() {
421 if idx > 0 {
422 write!(w, ", ")?;
423 }
424
425 write!(w, "typename T{}", pt.template_idx)?;
426 }
427
428 writeln!(w, ">")?;
429 write!(w, " inline ")?;
430 write_type(&f.ret, &mut *w)?;
431 write!(w, "{}(", f.name)?;
432
433 let new_params = f
434 .params
435 .iter()
436 .enumerate()
437 .filter(|(_, param)| param.poly_value.is_none());
438
439 let mut first = true;
440
441 for (idx, arg) in new_params {
442 if !first {
443 write!(w, ",")?;
444 }
445
446 first = false;
447
448 write!(w, "\n ")?;
449
450 if arg.poly_type.is_none() {
451 write_type(&arg.ty, &mut *w)?;
452 } else {
453 let pt = poly_types.iter().find(|pt| pt.value_pos == idx).unwrap();
454
455 let ty = Ctype {
456 typename: format!("T{}", pt.template_idx),
457 ..arg.ty.inner().clone()
458 };
459
460 write_type(&ty, &mut *w)?;
461 }
462
463 if let Some(name) = &arg.name {
464 write!(w, "{}", **name)?;
465 } else {
466 write!(w, "unnamed_{}", idx)?;
467 }
468 }
469
470 write!(w, "\n ")?;
471 writeln!(w, ")")?;
472
473 writeln!(w, " {{")?;
474 write!(w, " return this->{}(", f.name)?;
475
476 for (idx, arg) in f.params.iter().enumerate() {
477 if idx > 0 {
478 write!(w, ",")?;
479 }
480
481 write!(w, "\n ")?;
482
483 if let Some(poly_value) = arg.poly_value {
484 let pt = poly_types
485 .iter()
486 .find(|pt| pt.value_pos == poly_value)
487 .unwrap();
488 write!(w, "&::nucom::guid_of<T{}>", pt.template_idx)?;
489 } else {
490 let needs_cast = arg.poly_type.is_some();
491
492 if needs_cast {
493 write!(w, "reinterpret_cast<")?;
494 write_type_space(&arg.ty, &mut *w, false)?;
495 write!(w, ">(")?;
496 }
497
498 if let Some(name) = &arg.name {
499 write!(w, "{}", **name)?;
500 } else {
501 write!(w, "unnamed_{}", idx)?;
502 }
503
504 if needs_cast {
505 write!(w, ")")?;
506 }
507 }
508 }
509
510 write!(w, "\n ")?;
511 writeln!(w, ");")?;
512 writeln!(w, " }}")?;
513 }
514
515 Ok(())
516}