1 use crate::gen::block::Block;
2 use crate::gen::nested::NamespaceEntries;
3 use crate::gen::out::OutFile;
4 use crate::gen::{builtin, include, Opt};
5 use crate::syntax::atom::Atom::{self, *};
6 use crate::syntax::instantiate::{ImplKey, NamedImplKey};
7 use crate::syntax::map::UnorderedMap as Map;
8 use crate::syntax::set::UnorderedSet;
9 use crate::syntax::symbol::{self, Symbol};
10 use crate::syntax::trivial::{self, TrivialReason};
11 use crate::syntax::{
12     derive, mangle, Api, Doc, Enum, EnumRepr, ExternFn, ExternType, Pair, Signature, Struct, Trait,
13     Type, TypeAlias, Types, Var,
14 };
15 use proc_macro2::Ident;
16 
17 pub(super) fn gen(apis: &[Api], types: &Types, opt: &Opt, header: bool) -> Vec<u8> {
18     let mut out_file = OutFile::new(header, opt, types);
19     let out = &mut out_file;
20 
21     pick_includes_and_builtins(out, apis);
22     out.include.extend(&opt.include);
23 
24     write_forward_declarations(out, apis);
25     write_data_structures(out, apis);
26     write_functions(out, apis);
27     write_generic_instantiations(out);
28 
29     builtin::write(out);
30     include::write(out);
31 
32     out_file.content()
33 }
34 
write_forward_declarationsnull35 fn write_forward_declarations(out: &mut OutFile, apis: &[Api]) {
36     let needs_forward_declaration = |api: &&Api| match api {
37         Api::Struct(_) | Api::CxxType(_) | Api::RustType(_) => true,
38         Api::Enum(enm) => !out.types.cxx.contains(&enm.name.rust),
39         _ => false,
40     };
41 
42     let apis_by_namespace =
43         NamespaceEntries::new(apis.iter().filter(needs_forward_declaration).collect());
44 
45     write(out, &apis_by_namespace, 0);
46 
47     fn write(out: &mut OutFile, ns_entries: &NamespaceEntries, indent: usize) {
48         let apis = ns_entries.direct_content();
49 
50         for api in apis {
51             write!(out, "{:1$}", "", indent);
52             match api {
53                 Api::Struct(strct) => write_struct_decl(out, &strct.name),
54                 Api::Enum(enm) => write_enum_decl(out, enm),
55                 Api::CxxType(ety) => write_struct_using(out, &ety.name),
56                 Api::RustType(ety) => write_struct_decl(out, &ety.name),
57                 _ => unreachable!(),
58             }
59         }
60 
61         for (namespace, nested_ns_entries) in ns_entries.nested_content() {
62             writeln!(out, "{:2$}namespace {} {{", "", namespace, indent);
63             write(out, nested_ns_entries, indent + 2);
64             writeln!(out, "{:1$}}}", "", indent);
65         }
66     }
67 }
68 
write_data_structuresnull69 fn write_data_structures<'a>(out: &mut OutFile<'a>, apis: &'a [Api]) {
70     let mut methods_for_type = Map::new();
71     for api in apis {
72         if let Api::CxxFunction(efn) | Api::RustFunction(efn) = api {
73             if let Some(receiver) = &efn.sig.receiver {
74                 methods_for_type
75                     .entry(&receiver.ty.rust)
76                     .or_insert_with(Vec::new)
77                     .push(efn);
78             }
79         }
80     }
81 
82     let mut structs_written = UnorderedSet::new();
83     let mut toposorted_structs = out.types.toposorted_structs.iter();
84     for api in apis {
85         match api {
86             Api::Struct(strct) if !structs_written.contains(&strct.name.rust) => {
87                 for next in &mut toposorted_structs {
88                     if !out.types.cxx.contains(&strct.name.rust) {
89                         out.next_section();
90                         let methods = methods_for_type
91                             .get(&strct.name.rust)
92                             .map(Vec::as_slice)
93                             .unwrap_or_default();
94                         write_struct(out, next, methods);
95                     }
96                     structs_written.insert(&next.name.rust);
97                     if next.name.rust == strct.name.rust {
98                         break;
99                     }
100                 }
101             }
102             Api::Enum(enm) => {
103                 out.next_section();
104                 if !out.types.cxx.contains(&enm.name.rust) {
105                     write_enum(out, enm);
106                 } else if !enm.variants_from_header {
107                     check_enum(out, enm);
108                 }
109             }
110             Api::RustType(ety) => {
111                 out.next_section();
112                 let methods = methods_for_type
113                     .get(&ety.name.rust)
114                     .map(Vec::as_slice)
115                     .unwrap_or_default();
116                 write_opaque_type(out, ety, methods);
117             }
118             _ => {}
119         }
120     }
121 
122     if out.header {
123         return;
124     }
125 
126     out.set_namespace(Default::default());
127 
128     out.next_section();
129     for api in apis {
130         if let Api::TypeAlias(ety) = api {
131             if let Some(reasons) = out.types.required_trivial.get(&ety.name.rust) {
132                 check_trivial_extern_type(out, ety, reasons)
133             }
134         }
135     }
136 }
137 
write_functionsnull138 fn write_functions<'a>(out: &mut OutFile<'a>, apis: &'a [Api]) {
139     if !out.header {
140         for api in apis {
141             match api {
142                 Api::Struct(strct) => write_struct_operator_decls(out, strct),
143                 Api::RustType(ety) => write_opaque_type_layout_decls(out, ety),
144                 Api::CxxFunction(efn) => write_cxx_function_shim(out, efn),
145                 Api::RustFunction(efn) => write_rust_function_decl(out, efn),
146                 _ => {}
147             }
148         }
149 
150         write_std_specializations(out, apis);
151     }
152 
153     for api in apis {
154         match api {
155             Api::Struct(strct) => write_struct_operators(out, strct),
156             Api::RustType(ety) => write_opaque_type_layout(out, ety),
157             Api::RustFunction(efn) => {
158                 out.next_section();
159                 write_rust_function_shim(out, efn);
160             }
161             _ => {}
162         }
163     }
164 }
165 
write_std_specializationsnull166 fn write_std_specializations(out: &mut OutFile, apis: &[Api]) {
167     out.set_namespace(Default::default());
168     out.begin_block(Block::Namespace("std"));
169 
170     for api in apis {
171         if let Api::Struct(strct) = api {
172             if derive::contains(&strct.derives, Trait::Hash) {
173                 out.next_section();
174                 out.include.cstddef = true;
175                 out.include.functional = true;
176                 let qualified = strct.name.to_fully_qualified();
177                 writeln!(out, "template <> struct hash<{}> {{", qualified);
178                 writeln!(
179                     out,
180                     "  ::std::size_t operator()({} const &self) const noexcept {{",
181                     qualified,
182                 );
183                 let link_name = mangle::operator(&strct.name, "hash");
184                 write!(out, "    return ::");
185                 for name in &strct.name.namespace {
186                     write!(out, "{}::", name);
187                 }
188                 writeln!(out, "{}(self);", link_name);
189                 writeln!(out, "  }}");
190                 writeln!(out, "}};");
191             }
192         }
193     }
194 
195     out.end_block(Block::Namespace("std"));
196 }
197 
pick_includes_and_builtinsnull198 fn pick_includes_and_builtins(out: &mut OutFile, apis: &[Api]) {
199     for api in apis {
200         if let Api::Include(include) = api {
201             out.include.insert(include);
202         }
203     }
204 
205     for ty in out.types {
206         match ty {
207             Type::Ident(ident) => match Atom::from(&ident.rust) {
208                 Some(U8) | Some(U16) | Some(U32) | Some(U64) | Some(I8) | Some(I16) | Some(I32)
209                 | Some(I64) => out.include.cstdint = true,
210                 Some(Usize) => out.include.cstddef = true,
211                 Some(Isize) => out.builtin.rust_isize = true,
212                 Some(CxxString) => out.include.string = true,
213                 Some(RustString) => out.builtin.rust_string = true,
214                 Some(Bool) | Some(Char) | Some(F32) | Some(F64) | None => {}
215             },
216             Type::RustBox(_) => out.builtin.rust_box = true,
217             Type::RustVec(_) => out.builtin.rust_vec = true,
218             Type::UniquePtr(_) => out.include.memory = true,
219             Type::SharedPtr(_) | Type::WeakPtr(_) => out.include.memory = true,
220             Type::Str(_) => out.builtin.rust_str = true,
221             Type::CxxVector(_) => out.include.vector = true,
222             Type::Fn(_) => out.builtin.rust_fn = true,
223             Type::SliceRef(_) => out.builtin.rust_slice = true,
224             Type::Array(_) => out.include.array = true,
225             Type::Ref(_) | Type::Void(_) | Type::Ptr(_) => {}
226         }
227     }
228 }
229 
write_docnull230 fn write_doc(out: &mut OutFile, indent: &str, doc: &Doc) {
231     let mut lines = 0;
232     for line in doc.to_string().lines() {
233         if out.opt.doxygen {
234             writeln!(out, "{}///{}", indent, line);
235         } else {
236             writeln!(out, "{}//{}", indent, line);
237         }
238         lines += 1;
239     }
240     // According to https://www.doxygen.nl/manual/docblocks.html, Doxygen only
241     // interprets `///` as a Doxygen comment block if there are at least 2 of
242     // them. In Rust, a single `///` is definitely still documentation so we
243     // make sure to propagate that as a Doxygen comment.
244     if out.opt.doxygen && lines == 1 {
245         writeln!(out, "{}///", indent);
246     }
247 }
248 
write_structnull249 fn write_struct<'a>(out: &mut OutFile<'a>, strct: &'a Struct, methods: &[&ExternFn]) {
250     let operator_eq = derive::contains(&strct.derives, Trait::PartialEq);
251     let operator_ord = derive::contains(&strct.derives, Trait::PartialOrd);
252 
253     out.set_namespace(&strct.name.namespace);
254     let guard = format!("CXXBRIDGE1_STRUCT_{}", strct.name.to_symbol());
255     writeln!(out, "#ifndef {}", guard);
256     writeln!(out, "#define {}", guard);
257     write_doc(out, "", &strct.doc);
258     writeln!(out, "struct {} final {{", strct.name.cxx);
259 
260     for field in &strct.fields {
261         write_doc(out, "  ", &field.doc);
262         write!(out, "  ");
263         write_type_space(out, &field.ty);
264         writeln!(out, "{};", field.name.cxx);
265     }
266 
267     out.next_section();
268 
269     for method in methods {
270         if !method.doc.is_empty() {
271             out.next_section();
272         }
273         write_doc(out, "  ", &method.doc);
274         write!(out, "  ");
275         let sig = &method.sig;
276         let local_name = method.name.cxx.to_string();
277         let indirect_call = false;
278         write_rust_function_shim_decl(out, &local_name, sig, indirect_call);
279         writeln!(out, ";");
280         if !method.doc.is_empty() {
281             out.next_section();
282         }
283     }
284 
285     if operator_eq {
286         writeln!(
287             out,
288             "  bool operator==({} const &) const noexcept;",
289             strct.name.cxx,
290         );
291         writeln!(
292             out,
293             "  bool operator!=({} const &) const noexcept;",
294             strct.name.cxx,
295         );
296     }
297 
298     if operator_ord {
299         writeln!(
300             out,
301             "  bool operator<({} const &) const noexcept;",
302             strct.name.cxx,
303         );
304         writeln!(
305             out,
306             "  bool operator<=({} const &) const noexcept;",
307             strct.name.cxx,
308         );
309         writeln!(
310             out,
311             "  bool operator>({} const &) const noexcept;",
312             strct.name.cxx,
313         );
314         writeln!(
315             out,
316             "  bool operator>=({} const &) const noexcept;",
317             strct.name.cxx,
318         );
319     }
320 
321     out.include.type_traits = true;
322     writeln!(out, "  using IsRelocatable = ::std::true_type;");
323 
324     writeln!(out, "}};");
325     writeln!(out, "#endif // {}", guard);
326 }
327 
write_struct_declnull328 fn write_struct_decl(out: &mut OutFile, ident: &Pair) {
329     writeln!(out, "struct {};", ident.cxx);
330 }
331 
write_enum_declnull332 fn write_enum_decl(out: &mut OutFile, enm: &Enum) {
333     let repr = match &enm.repr {
334         #[cfg(feature = "experimental-enum-variants-from-header")]
335         EnumRepr::Foreign { .. } => return,
336         EnumRepr::Native { atom, .. } => *atom,
337     };
338     write!(out, "enum class {} : ", enm.name.cxx);
339     write_atom(out, repr);
340     writeln!(out, ";");
341 }
342 
write_struct_usingnull343 fn write_struct_using(out: &mut OutFile, ident: &Pair) {
344     writeln!(out, "using {} = {};", ident.cxx, ident.to_fully_qualified());
345 }
346 
write_opaque_typenull347 fn write_opaque_type<'a>(out: &mut OutFile<'a>, ety: &'a ExternType, methods: &[&ExternFn]) {
348     out.set_namespace(&ety.name.namespace);
349     let guard = format!("CXXBRIDGE1_STRUCT_{}", ety.name.to_symbol());
350     writeln!(out, "#ifndef {}", guard);
351     writeln!(out, "#define {}", guard);
352     write_doc(out, "", &ety.doc);
353 
354     out.builtin.opaque = true;
355     writeln!(
356         out,
357         "struct {} final : public ::rust::Opaque {{",
358         ety.name.cxx,
359     );
360 
361     for (i, method) in methods.iter().enumerate() {
362         if i > 0 && !method.doc.is_empty() {
363             out.next_section();
364         }
365         write_doc(out, "  ", &method.doc);
366         write!(out, "  ");
367         let sig = &method.sig;
368         let local_name = method.name.cxx.to_string();
369         let indirect_call = false;
370         write_rust_function_shim_decl(out, &local_name, sig, indirect_call);
371         writeln!(out, ";");
372         if !method.doc.is_empty() {
373             out.next_section();
374         }
375     }
376 
377     writeln!(out, "  ~{}() = delete;", ety.name.cxx);
378     writeln!(out);
379 
380     out.builtin.layout = true;
381     out.include.cstddef = true;
382     writeln!(out, "private:");
383     writeln!(out, "  friend ::rust::layout;");
384     writeln!(out, "  struct layout {{");
385     writeln!(out, "    static ::std::size_t size() noexcept;");
386     writeln!(out, "    static ::std::size_t align() noexcept;");
387     writeln!(out, "  }};");
388     writeln!(out, "}};");
389     writeln!(out, "#endif // {}", guard);
390 }
391 
write_enumnull392 fn write_enum<'a>(out: &mut OutFile<'a>, enm: &'a Enum) {
393     let repr = match &enm.repr {
394         #[cfg(feature = "experimental-enum-variants-from-header")]
395         EnumRepr::Foreign { .. } => return,
396         EnumRepr::Native { atom, .. } => *atom,
397     };
398     out.set_namespace(&enm.name.namespace);
399     let guard = format!("CXXBRIDGE1_ENUM_{}", enm.name.to_symbol());
400     writeln!(out, "#ifndef {}", guard);
401     writeln!(out, "#define {}", guard);
402     write_doc(out, "", &enm.doc);
403     write!(out, "enum class {} : ", enm.name.cxx);
404     write_atom(out, repr);
405     writeln!(out, " {{");
406     for variant in &enm.variants {
407         write_doc(out, "  ", &variant.doc);
408         writeln!(out, "  {} = {},", variant.name.cxx, variant.discriminant);
409     }
410     writeln!(out, "}};");
411     writeln!(out, "#endif // {}", guard);
412 }
413 
check_enumnull414 fn check_enum<'a>(out: &mut OutFile<'a>, enm: &'a Enum) {
415     let repr = match &enm.repr {
416         #[cfg(feature = "experimental-enum-variants-from-header")]
417         EnumRepr::Foreign { .. } => return,
418         EnumRepr::Native { atom, .. } => *atom,
419     };
420     out.set_namespace(&enm.name.namespace);
421     out.include.type_traits = true;
422     writeln!(
423         out,
424         "static_assert(::std::is_enum<{}>::value, \"expected enum\");",
425         enm.name.cxx,
426     );
427     write!(out, "static_assert(sizeof({}) == sizeof(", enm.name.cxx);
428     write_atom(out, repr);
429     writeln!(out, "), \"incorrect size\");");
430     for variant in &enm.variants {
431         write!(out, "static_assert(static_cast<");
432         write_atom(out, repr);
433         writeln!(
434             out,
435             ">({}::{}) == {}, \"disagrees with the value in #[cxx::bridge]\");",
436             enm.name.cxx, variant.name.cxx, variant.discriminant,
437         );
438     }
439 }
440 
check_trivial_extern_typenull441 fn check_trivial_extern_type(out: &mut OutFile, alias: &TypeAlias, reasons: &[TrivialReason]) {
442     // NOTE: The following static assertion is just nice-to-have and not
443     // necessary for soundness. That's because triviality is always declared by
444     // the user in the form of an unsafe impl of cxx::ExternType:
445     //
446     //     unsafe impl ExternType for MyType {
447     //         type Id = cxx::type_id!("...");
448     //         type Kind = cxx::kind::Trivial;
449     //     }
450     //
451     // Since the user went on the record with their unsafe impl to unsafely
452     // claim they KNOW that the type is trivial, it's fine for that to be on
453     // them if that were wrong. However, in practice correctly reasoning about
454     // the relocatability of C++ types is challenging, particularly if the type
455     // definition were to change over time, so for now we add this check.
456     //
457     // There may be legitimate reasons to opt out of this assertion for support
458     // of types that the programmer knows are soundly Rust-movable despite not
459     // being recognized as such by the C++ type system due to a move constructor
460     // or destructor. To opt out of the relocatability check, they need to do
461     // one of the following things in any header used by `include!` in their
462     // bridge.
463     //
464     //      --- if they define the type:
465     //      struct MyType {
466     //        ...
467     //    +   using IsRelocatable = std::true_type;
468     //      };
469     //
470     //      --- otherwise:
471     //    + template <>
472     //    + struct rust::IsRelocatable<MyType> : std::true_type {};
473     //
474 
475     let id = alias.name.to_fully_qualified();
476     out.builtin.relocatable = true;
477     writeln!(out, "static_assert(");
478     if reasons
479         .iter()
480         .all(|r| matches!(r, TrivialReason::StructField(_) | TrivialReason::VecElement))
481     {
482         // If the type is only used as a struct field or Vec element, not as
483         // by-value function argument or return value, then C array of trivially
484         // relocatable type is also permissible.
485         //
486         //     --- means something sane:
487         //     struct T { char buf[N]; };
488         //
489         //     --- means something totally different:
490         //     void f(char buf[N]);
491         //
492         out.builtin.relocatable_or_array = true;
493         writeln!(out, "    ::rust::IsRelocatableOrArray<{}>::value,", id);
494     } else {
495         writeln!(out, "    ::rust::IsRelocatable<{}>::value,", id);
496     }
497     writeln!(
498         out,
499         "    \"type {} should be trivially move constructible and trivially destructible in C++ to be used as {} in Rust\");",
500         id.trim_start_matches("::"),
501         trivial::as_what(&alias.name, reasons),
502     );
503 }
504 
write_struct_operator_declsnull505 fn write_struct_operator_decls<'a>(out: &mut OutFile<'a>, strct: &'a Struct) {
506     out.set_namespace(&strct.name.namespace);
507     out.begin_block(Block::ExternC);
508 
509     if derive::contains(&strct.derives, Trait::PartialEq) {
510         let link_name = mangle::operator(&strct.name, "eq");
511         writeln!(
512             out,
513             "bool {}({1} const &, {1} const &) noexcept;",
514             link_name, strct.name.cxx,
515         );
516 
517         if !derive::contains(&strct.derives, Trait::Eq) {
518             let link_name = mangle::operator(&strct.name, "ne");
519             writeln!(
520                 out,
521                 "bool {}({1} const &, {1} const &) noexcept;",
522                 link_name, strct.name.cxx,
523             );
524         }
525     }
526 
527     if derive::contains(&strct.derives, Trait::PartialOrd) {
528         let link_name = mangle::operator(&strct.name, "lt");
529         writeln!(
530             out,
531             "bool {}({1} const &, {1} const &) noexcept;",
532             link_name, strct.name.cxx,
533         );
534 
535         let link_name = mangle::operator(&strct.name, "le");
536         writeln!(
537             out,
538             "bool {}({1} const &, {1} const &) noexcept;",
539             link_name, strct.name.cxx,
540         );
541 
542         if !derive::contains(&strct.derives, Trait::Ord) {
543             let link_name = mangle::operator(&strct.name, "gt");
544             writeln!(
545                 out,
546                 "bool {}({1} const &, {1} const &) noexcept;",
547                 link_name, strct.name.cxx,
548             );
549 
550             let link_name = mangle::operator(&strct.name, "ge");
551             writeln!(
552                 out,
553                 "bool {}({1} const &, {1} const &) noexcept;",
554                 link_name, strct.name.cxx,
555             );
556         }
557     }
558 
559     if derive::contains(&strct.derives, Trait::Hash) {
560         out.include.cstddef = true;
561         let link_name = mangle::operator(&strct.name, "hash");
562         writeln!(
563             out,
564             "::std::size_t {}({} const &) noexcept;",
565             link_name, strct.name.cxx,
566         );
567     }
568 
569     out.end_block(Block::ExternC);
570 }
571 
write_struct_operatorsnull572 fn write_struct_operators<'a>(out: &mut OutFile<'a>, strct: &'a Struct) {
573     if out.header {
574         return;
575     }
576 
577     out.set_namespace(&strct.name.namespace);
578 
579     if derive::contains(&strct.derives, Trait::PartialEq) {
580         out.next_section();
581         writeln!(
582             out,
583             "bool {0}::operator==({0} const &rhs) const noexcept {{",
584             strct.name.cxx,
585         );
586         let link_name = mangle::operator(&strct.name, "eq");
587         writeln!(out, "  return {}(*this, rhs);", link_name);
588         writeln!(out, "}}");
589 
590         out.next_section();
591         writeln!(
592             out,
593             "bool {0}::operator!=({0} const &rhs) const noexcept {{",
594             strct.name.cxx,
595         );
596         if derive::contains(&strct.derives, Trait::Eq) {
597             writeln!(out, "  return !(*this == rhs);");
598         } else {
599             let link_name = mangle::operator(&strct.name, "ne");
600             writeln!(out, "  return {}(*this, rhs);", link_name);
601         }
602         writeln!(out, "}}");
603     }
604 
605     if derive::contains(&strct.derives, Trait::PartialOrd) {
606         out.next_section();
607         writeln!(
608             out,
609             "bool {0}::operator<({0} const &rhs) const noexcept {{",
610             strct.name.cxx,
611         );
612         let link_name = mangle::operator(&strct.name, "lt");
613         writeln!(out, "  return {}(*this, rhs);", link_name);
614         writeln!(out, "}}");
615 
616         out.next_section();
617         writeln!(
618             out,
619             "bool {0}::operator<=({0} const &rhs) const noexcept {{",
620             strct.name.cxx,
621         );
622         let link_name = mangle::operator(&strct.name, "le");
623         writeln!(out, "  return {}(*this, rhs);", link_name);
624         writeln!(out, "}}");
625 
626         out.next_section();
627         writeln!(
628             out,
629             "bool {0}::operator>({0} const &rhs) const noexcept {{",
630             strct.name.cxx,
631         );
632         if derive::contains(&strct.derives, Trait::Ord) {
633             writeln!(out, "  return !(*this <= rhs);");
634         } else {
635             let link_name = mangle::operator(&strct.name, "gt");
636             writeln!(out, "  return {}(*this, rhs);", link_name);
637         }
638         writeln!(out, "}}");
639 
640         out.next_section();
641         writeln!(
642             out,
643             "bool {0}::operator>=({0} const &rhs) const noexcept {{",
644             strct.name.cxx,
645         );
646         if derive::contains(&strct.derives, Trait::Ord) {
647             writeln!(out, "  return !(*this < rhs);");
648         } else {
649             let link_name = mangle::operator(&strct.name, "ge");
650             writeln!(out, "  return {}(*this, rhs);", link_name);
651         }
652         writeln!(out, "}}");
653     }
654 }
655 
write_opaque_type_layout_declsnull656 fn write_opaque_type_layout_decls<'a>(out: &mut OutFile<'a>, ety: &'a ExternType) {
657     out.set_namespace(&ety.name.namespace);
658     out.begin_block(Block::ExternC);
659 
660     let link_name = mangle::operator(&ety.name, "sizeof");
661     writeln!(out, "::std::size_t {}() noexcept;", link_name);
662 
663     let link_name = mangle::operator(&ety.name, "alignof");
664     writeln!(out, "::std::size_t {}() noexcept;", link_name);
665 
666     out.end_block(Block::ExternC);
667 }
668 
write_opaque_type_layoutnull669 fn write_opaque_type_layout<'a>(out: &mut OutFile<'a>, ety: &'a ExternType) {
670     if out.header {
671         return;
672     }
673 
674     out.set_namespace(&ety.name.namespace);
675 
676     out.next_section();
677     let link_name = mangle::operator(&ety.name, "sizeof");
678     writeln!(
679         out,
680         "::std::size_t {}::layout::size() noexcept {{",
681         ety.name.cxx,
682     );
683     writeln!(out, "  return {}();", link_name);
684     writeln!(out, "}}");
685 
686     out.next_section();
687     let link_name = mangle::operator(&ety.name, "alignof");
688     writeln!(
689         out,
690         "::std::size_t {}::layout::align() noexcept {{",
691         ety.name.cxx,
692     );
693     writeln!(out, "  return {}();", link_name);
694     writeln!(out, "}}");
695 }
696 
begin_function_definitionnull697 fn begin_function_definition(out: &mut OutFile) {
698     if let Some(annotation) = &out.opt.cxx_impl_annotations {
699         write!(out, "{} ", annotation);
700     }
701 }
702 
write_cxx_function_shimnull703 fn write_cxx_function_shim<'a>(out: &mut OutFile<'a>, efn: &'a ExternFn) {
704     out.next_section();
705     out.set_namespace(&efn.name.namespace);
706     out.begin_block(Block::ExternC);
707     begin_function_definition(out);
708     if efn.throws {
709         out.builtin.ptr_len = true;
710         write!(out, "::rust::repr::PtrLen ");
711     } else {
712         write_extern_return_type_space(out, &efn.ret);
713     }
714     let mangled = mangle::extern_fn(efn, out.types);
715     write!(out, "{}(", mangled);
716     if let Some(receiver) = &efn.receiver {
717         write!(
718             out,
719             "{}",
720             out.types.resolve(&receiver.ty).name.to_fully_qualified(),
721         );
722         if !receiver.mutable {
723             write!(out, " const");
724         }
725         write!(out, " &self");
726     }
727     for (i, arg) in efn.args.iter().enumerate() {
728         if i > 0 || efn.receiver.is_some() {
729             write!(out, ", ");
730         }
731         if arg.ty == RustString {
732             write_type_space(out, &arg.ty);
733             write!(out, "const *{}", arg.name.cxx);
734         } else if let Type::RustVec(_) = arg.ty {
735             write_type_space(out, &arg.ty);
736             write!(out, "const *{}", arg.name.cxx);
737         } else {
738             write_extern_arg(out, arg);
739         }
740     }
741     let indirect_return = indirect_return(efn, out.types);
742     if indirect_return {
743         if !efn.args.is_empty() || efn.receiver.is_some() {
744             write!(out, ", ");
745         }
746         write_indirect_return_type_space(out, efn.ret.as_ref().unwrap());
747         write!(out, "*return$");
748     }
749     writeln!(out, ") noexcept {{");
750     write!(out, "  ");
751     write_return_type(out, &efn.ret);
752     match &efn.receiver {
753         None => write!(out, "(*{}$)(", efn.name.rust),
754         Some(receiver) => write!(
755             out,
756             "({}::*{}$)(",
757             out.types.resolve(&receiver.ty).name.to_fully_qualified(),
758             efn.name.rust,
759         ),
760     }
761     for (i, arg) in efn.args.iter().enumerate() {
762         if i > 0 {
763             write!(out, ", ");
764         }
765         write_type(out, &arg.ty);
766     }
767     write!(out, ")");
768     if let Some(receiver) = &efn.receiver {
769         if !receiver.mutable {
770             write!(out, " const");
771         }
772     }
773     write!(out, " = ");
774     match &efn.receiver {
775         None => write!(out, "{}", efn.name.to_fully_qualified()),
776         Some(receiver) => write!(
777             out,
778             "&{}::{}",
779             out.types.resolve(&receiver.ty).name.to_fully_qualified(),
780             efn.name.cxx,
781         ),
782     }
783     writeln!(out, ";");
784     write!(out, "  ");
785     if efn.throws {
786         out.builtin.ptr_len = true;
787         out.builtin.trycatch = true;
788         writeln!(out, "::rust::repr::PtrLen throw$;");
789         writeln!(out, "  ::rust::behavior::trycatch(");
790         writeln!(out, "      [&] {{");
791         write!(out, "        ");
792     }
793     if indirect_return {
794         out.include.new = true;
795         write!(out, "new (return$) ");
796         write_indirect_return_type(out, efn.ret.as_ref().unwrap());
797         write!(out, "(");
798     } else if efn.ret.is_some() {
799         write!(out, "return ");
800     }
801     match &efn.ret {
802         Some(Type::Ref(_)) => write!(out, "&"),
803         Some(Type::Str(_)) if !indirect_return => {
804             out.builtin.rust_str_repr = true;
805             write!(out, "::rust::impl<::rust::Str>::repr(");
806         }
807         Some(ty @ Type::SliceRef(_)) if !indirect_return => {
808             out.builtin.rust_slice_repr = true;
809             write!(out, "::rust::impl<");
810             write_type(out, ty);
811             write!(out, ">::repr(");
812         }
813         _ => {}
814     }
815     match &efn.receiver {
816         None => write!(out, "{}$(", efn.name.rust),
817         Some(_) => write!(out, "(self.*{}$)(", efn.name.rust),
818     }
819     for (i, arg) in efn.args.iter().enumerate() {
820         if i > 0 {
821             write!(out, ", ");
822         }
823         if let Type::RustBox(_) = &arg.ty {
824             write_type(out, &arg.ty);
825             write!(out, "::from_raw({})", arg.name.cxx);
826         } else if let Type::UniquePtr(_) = &arg.ty {
827             write_type(out, &arg.ty);
828             write!(out, "({})", arg.name.cxx);
829         } else if arg.ty == RustString {
830             out.builtin.unsafe_bitcopy = true;
831             write!(
832                 out,
833                 "::rust::String(::rust::unsafe_bitcopy, *{})",
834                 arg.name.cxx,
835             );
836         } else if let Type::RustVec(_) = arg.ty {
837             out.builtin.unsafe_bitcopy = true;
838             write_type(out, &arg.ty);
839             write!(out, "(::rust::unsafe_bitcopy, *{})", arg.name.cxx);
840         } else if out.types.needs_indirect_abi(&arg.ty) {
841             out.include.utility = true;
842             write!(out, "::std::move(*{})", arg.name.cxx);
843         } else {
844             write!(out, "{}", arg.name.cxx);
845         }
846     }
847     write!(out, ")");
848     match &efn.ret {
849         Some(Type::RustBox(_)) => write!(out, ".into_raw()"),
850         Some(Type::UniquePtr(_)) => write!(out, ".release()"),
851         Some(Type::Str(_)) | Some(Type::SliceRef(_)) if !indirect_return => write!(out, ")"),
852         _ => {}
853     }
854     if indirect_return {
855         write!(out, ")");
856     }
857     writeln!(out, ";");
858     if efn.throws {
859         writeln!(out, "        throw$.ptr = nullptr;");
860         writeln!(out, "      }},");
861         writeln!(out, "      ::rust::detail::Fail(throw$));");
862         writeln!(out, "  return throw$;");
863     }
864     writeln!(out, "}}");
865     for arg in &efn.args {
866         if let Type::Fn(f) = &arg.ty {
867             let var = &arg.name;
868             write_function_pointer_trampoline(out, efn, var, f);
869         }
870     }
871     out.end_block(Block::ExternC);
872 }
873 
write_function_pointer_trampolinenull874 fn write_function_pointer_trampoline(out: &mut OutFile, efn: &ExternFn, var: &Pair, f: &Signature) {
875     let r_trampoline = mangle::r_trampoline(efn, var, out.types);
876     let indirect_call = true;
877     write_rust_function_decl_impl(out, &r_trampoline, f, indirect_call);
878 
879     out.next_section();
880     let c_trampoline = mangle::c_trampoline(efn, var, out.types).to_string();
881     let doc = Doc::new();
882     write_rust_function_shim_impl(out, &c_trampoline, f, &doc, &r_trampoline, indirect_call);
883 }
884 
write_rust_function_declnull885 fn write_rust_function_decl<'a>(out: &mut OutFile<'a>, efn: &'a ExternFn) {
886     out.set_namespace(&efn.name.namespace);
887     out.begin_block(Block::ExternC);
888     let link_name = mangle::extern_fn(efn, out.types);
889     let indirect_call = false;
890     write_rust_function_decl_impl(out, &link_name, efn, indirect_call);
891     out.end_block(Block::ExternC);
892 }
893 
write_rust_function_decl_implnull894 fn write_rust_function_decl_impl(
895     out: &mut OutFile,
896     link_name: &Symbol,
897     sig: &Signature,
898     indirect_call: bool,
899 ) {
900     out.next_section();
901     if sig.throws {
902         out.builtin.ptr_len = true;
903         write!(out, "::rust::repr::PtrLen ");
904     } else {
905         write_extern_return_type_space(out, &sig.ret);
906     }
907     write!(out, "{}(", link_name);
908     let mut needs_comma = false;
909     if let Some(receiver) = &sig.receiver {
910         write!(
911             out,
912             "{}",
913             out.types.resolve(&receiver.ty).name.to_fully_qualified(),
914         );
915         if !receiver.mutable {
916             write!(out, " const");
917         }
918         write!(out, " &self");
919         needs_comma = true;
920     }
921     for arg in &sig.args {
922         if needs_comma {
923             write!(out, ", ");
924         }
925         write_extern_arg(out, arg);
926         needs_comma = true;
927     }
928     if indirect_return(sig, out.types) {
929         if needs_comma {
930             write!(out, ", ");
931         }
932         match sig.ret.as_ref().unwrap() {
933             Type::Ref(ret) => {
934                 write_type_space(out, &ret.inner);
935                 if !ret.mutable {
936                     write!(out, "const ");
937                 }
938                 write!(out, "*");
939             }
940             ret => write_type_space(out, ret),
941         }
942         write!(out, "*return$");
943         needs_comma = true;
944     }
945     if indirect_call {
946         if needs_comma {
947             write!(out, ", ");
948         }
949         write!(out, "void *");
950     }
951     writeln!(out, ") noexcept;");
952 }
953 
write_rust_function_shimnull954 fn write_rust_function_shim<'a>(out: &mut OutFile<'a>, efn: &'a ExternFn) {
955     out.set_namespace(&efn.name.namespace);
956     let local_name = match &efn.sig.receiver {
957         None => efn.name.cxx.to_string(),
958         Some(receiver) => format!(
959             "{}::{}",
960             out.types.resolve(&receiver.ty).name.cxx,
961             efn.name.cxx,
962         ),
963     };
964     let doc = &efn.doc;
965     let invoke = mangle::extern_fn(efn, out.types);
966     let indirect_call = false;
967     write_rust_function_shim_impl(out, &local_name, efn, doc, &invoke, indirect_call);
968 }
969 
write_rust_function_shim_declnull970 fn write_rust_function_shim_decl(
971     out: &mut OutFile,
972     local_name: &str,
973     sig: &Signature,
974     indirect_call: bool,
975 ) {
976     begin_function_definition(out);
977     write_return_type(out, &sig.ret);
978     write!(out, "{}(", local_name);
979     for (i, arg) in sig.args.iter().enumerate() {
980         if i > 0 {
981             write!(out, ", ");
982         }
983         write_type_space(out, &arg.ty);
984         write!(out, "{}", arg.name.cxx);
985     }
986     if indirect_call {
987         if !sig.args.is_empty() {
988             write!(out, ", ");
989         }
990         write!(out, "void *extern$");
991     }
992     write!(out, ")");
993     if let Some(receiver) = &sig.receiver {
994         if !receiver.mutable {
995             write!(out, " const");
996         }
997     }
998     if !sig.throws {
999         write!(out, " noexcept");
1000     }
1001 }
1002 
write_rust_function_shim_implnull1003 fn write_rust_function_shim_impl(
1004     out: &mut OutFile,
1005     local_name: &str,
1006     sig: &Signature,
1007     doc: &Doc,
1008     invoke: &Symbol,
1009     indirect_call: bool,
1010 ) {
1011     if out.header && sig.receiver.is_some() {
1012         // We've already defined this inside the struct.
1013         return;
1014     }
1015     if sig.receiver.is_none() {
1016         // Member functions already documented at their declaration.
1017         write_doc(out, "", doc);
1018     }
1019     write_rust_function_shim_decl(out, local_name, sig, indirect_call);
1020     if out.header {
1021         writeln!(out, ";");
1022         return;
1023     }
1024     writeln!(out, " {{");
1025     for arg in &sig.args {
1026         if arg.ty != RustString && out.types.needs_indirect_abi(&arg.ty) {
1027             out.include.utility = true;
1028             out.builtin.manually_drop = true;
1029             write!(out, "  ::rust::ManuallyDrop<");
1030             write_type(out, &arg.ty);
1031             writeln!(out, "> {}$(::std::move({0}));", arg.name.cxx);
1032         }
1033     }
1034     write!(out, "  ");
1035     let indirect_return = indirect_return(sig, out.types);
1036     if indirect_return {
1037         out.builtin.maybe_uninit = true;
1038         write!(out, "::rust::MaybeUninit<");
1039         match sig.ret.as_ref().unwrap() {
1040             Type::Ref(ret) => {
1041                 write_type_space(out, &ret.inner);
1042                 if !ret.mutable {
1043                     write!(out, "const ");
1044                 }
1045                 write!(out, "*");
1046             }
1047             ret => write_type(out, ret),
1048         }
1049         writeln!(out, "> return$;");
1050         write!(out, "  ");
1051     } else if let Some(ret) = &sig.ret {
1052         write!(out, "return ");
1053         match ret {
1054             Type::RustBox(_) => {
1055                 write_type(out, ret);
1056                 write!(out, "::from_raw(");
1057             }
1058             Type::UniquePtr(_) => {
1059                 write_type(out, ret);
1060                 write!(out, "(");
1061             }
1062             Type::Ref(_) => write!(out, "*"),
1063             Type::Str(_) => {
1064                 out.builtin.rust_str_new_unchecked = true;
1065                 write!(out, "::rust::impl<::rust::Str>::new_unchecked(");
1066             }
1067             Type::SliceRef(_) => {
1068                 out.builtin.rust_slice_new = true;
1069                 write!(out, "::rust::impl<");
1070                 write_type(out, ret);
1071                 write!(out, ">::slice(");
1072             }
1073             _ => {}
1074         }
1075     }
1076     if sig.throws {
1077         out.builtin.ptr_len = true;
1078         write!(out, "::rust::repr::PtrLen error$ = ");
1079     }
1080     write!(out, "{}(", invoke);
1081     let mut needs_comma = false;
1082     if sig.receiver.is_some() {
1083         write!(out, "*this");
1084         needs_comma = true;
1085     }
1086     for arg in &sig.args {
1087         if needs_comma {
1088             write!(out, ", ");
1089         }
1090         if out.types.needs_indirect_abi(&arg.ty) {
1091             write!(out, "&");
1092         }
1093         write!(out, "{}", arg.name.cxx);
1094         match &arg.ty {
1095             Type::RustBox(_) => write!(out, ".into_raw()"),
1096             Type::UniquePtr(_) => write!(out, ".release()"),
1097             ty if ty != RustString && out.types.needs_indirect_abi(ty) => write!(out, "$.value"),
1098             _ => {}
1099         }
1100         needs_comma = true;
1101     }
1102     if indirect_return {
1103         if needs_comma {
1104             write!(out, ", ");
1105         }
1106         write!(out, "&return$.value");
1107         needs_comma = true;
1108     }
1109     if indirect_call {
1110         if needs_comma {
1111             write!(out, ", ");
1112         }
1113         write!(out, "extern$");
1114     }
1115     write!(out, ")");
1116     if !indirect_return {
1117         if let Some(ret) = &sig.ret {
1118             if let Type::RustBox(_) | Type::UniquePtr(_) | Type::Str(_) | Type::SliceRef(_) = ret {
1119                 write!(out, ")");
1120             }
1121         }
1122     }
1123     writeln!(out, ";");
1124     if sig.throws {
1125         out.builtin.rust_error = true;
1126         writeln!(out, "  if (error$.ptr) {{");
1127         writeln!(out, "    throw ::rust::impl<::rust::Error>::error(error$);");
1128         writeln!(out, "  }}");
1129     }
1130     if indirect_return {
1131         write!(out, "  return ");
1132         match sig.ret.as_ref().unwrap() {
1133             Type::Ref(_) => write!(out, "*return$.value"),
1134             _ => {
1135                 out.include.utility = true;
1136                 write!(out, "::std::move(return$.value)");
1137             }
1138         }
1139         writeln!(out, ";");
1140     }
1141     writeln!(out, "}}");
1142 }
1143 
write_return_typenull1144 fn write_return_type(out: &mut OutFile, ty: &Option<Type>) {
1145     match ty {
1146         None => write!(out, "void "),
1147         Some(ty) => write_type_space(out, ty),
1148     }
1149 }
1150 
indirect_returnnull1151 fn indirect_return(sig: &Signature, types: &Types) -> bool {
1152     sig.ret
1153         .as_ref()
1154         .map_or(false, |ret| sig.throws || types.needs_indirect_abi(ret))
1155 }
1156 
write_indirect_return_typenull1157 fn write_indirect_return_type(out: &mut OutFile, ty: &Type) {
1158     match ty {
1159         Type::RustBox(ty) | Type::UniquePtr(ty) => {
1160             write_type_space(out, &ty.inner);
1161             write!(out, "*");
1162         }
1163         Type::Ref(ty) => {
1164             write_type_space(out, &ty.inner);
1165             if !ty.mutable {
1166                 write!(out, "const ");
1167             }
1168             write!(out, "*");
1169         }
1170         _ => write_type(out, ty),
1171     }
1172 }
1173 
write_indirect_return_type_spacenull1174 fn write_indirect_return_type_space(out: &mut OutFile, ty: &Type) {
1175     write_indirect_return_type(out, ty);
1176     match ty {
1177         Type::RustBox(_) | Type::UniquePtr(_) | Type::Ref(_) => {}
1178         Type::Str(_) | Type::SliceRef(_) => write!(out, " "),
1179         _ => write_space_after_type(out, ty),
1180     }
1181 }
1182 
write_extern_return_type_spacenull1183 fn write_extern_return_type_space(out: &mut OutFile, ty: &Option<Type>) {
1184     match ty {
1185         Some(Type::RustBox(ty)) | Some(Type::UniquePtr(ty)) => {
1186             write_type_space(out, &ty.inner);
1187             write!(out, "*");
1188         }
1189         Some(Type::Ref(ty)) => {
1190             write_type_space(out, &ty.inner);
1191             if !ty.mutable {
1192                 write!(out, "const ");
1193             }
1194             write!(out, "*");
1195         }
1196         Some(Type::Str(_)) | Some(Type::SliceRef(_)) => {
1197             out.builtin.repr_fat = true;
1198             write!(out, "::rust::repr::Fat ");
1199         }
1200         Some(ty) if out.types.needs_indirect_abi(ty) => write!(out, "void "),
1201         _ => write_return_type(out, ty),
1202     }
1203 }
1204 
write_extern_argnull1205 fn write_extern_arg(out: &mut OutFile, arg: &Var) {
1206     match &arg.ty {
1207         Type::RustBox(ty) | Type::UniquePtr(ty) | Type::CxxVector(ty) => {
1208             write_type_space(out, &ty.inner);
1209             write!(out, "*");
1210         }
1211         _ => write_type_space(out, &arg.ty),
1212     }
1213     if out.types.needs_indirect_abi(&arg.ty) {
1214         write!(out, "*");
1215     }
1216     write!(out, "{}", arg.name.cxx);
1217 }
1218 
write_typenull1219 fn write_type(out: &mut OutFile, ty: &Type) {
1220     match ty {
1221         Type::Ident(ident) => match Atom::from(&ident.rust) {
1222             Some(atom) => write_atom(out, atom),
1223             None => write!(
1224                 out,
1225                 "{}",
1226                 out.types.resolve(ident).name.to_fully_qualified(),
1227             ),
1228         },
1229         Type::RustBox(ty) => {
1230             write!(out, "::rust::Box<");
1231             write_type(out, &ty.inner);
1232             write!(out, ">");
1233         }
1234         Type::RustVec(ty) => {
1235             write!(out, "::rust::Vec<");
1236             write_type(out, &ty.inner);
1237             write!(out, ">");
1238         }
1239         Type::UniquePtr(ptr) => {
1240             write!(out, "::std::unique_ptr<");
1241             write_type(out, &ptr.inner);
1242             write!(out, ">");
1243         }
1244         Type::SharedPtr(ptr) => {
1245             write!(out, "::std::shared_ptr<");
1246             write_type(out, &ptr.inner);
1247             write!(out, ">");
1248         }
1249         Type::WeakPtr(ptr) => {
1250             write!(out, "::std::weak_ptr<");
1251             write_type(out, &ptr.inner);
1252             write!(out, ">");
1253         }
1254         Type::CxxVector(ty) => {
1255             write!(out, "::std::vector<");
1256             write_type(out, &ty.inner);
1257             write!(out, ">");
1258         }
1259         Type::Ref(r) => {
1260             write_type_space(out, &r.inner);
1261             if !r.mutable {
1262                 write!(out, "const ");
1263             }
1264             write!(out, "&");
1265         }
1266         Type::Ptr(p) => {
1267             write_type_space(out, &p.inner);
1268             if !p.mutable {
1269                 write!(out, "const ");
1270             }
1271             write!(out, "*");
1272         }
1273         Type::Str(_) => {
1274             write!(out, "::rust::Str");
1275         }
1276         Type::SliceRef(slice) => {
1277             write!(out, "::rust::Slice<");
1278             write_type_space(out, &slice.inner);
1279             if slice.mutability.is_none() {
1280                 write!(out, "const");
1281             }
1282             write!(out, ">");
1283         }
1284         Type::Fn(f) => {
1285             write!(out, "::rust::Fn<");
1286             match &f.ret {
1287                 Some(ret) => write_type(out, ret),
1288                 None => write!(out, "void"),
1289             }
1290             write!(out, "(");
1291             for (i, arg) in f.args.iter().enumerate() {
1292                 if i > 0 {
1293                     write!(out, ", ");
1294                 }
1295                 write_type(out, &arg.ty);
1296             }
1297             write!(out, ")>");
1298         }
1299         Type::Array(a) => {
1300             write!(out, "::std::array<");
1301             write_type(out, &a.inner);
1302             write!(out, ", {}>", &a.len);
1303         }
1304         Type::Void(_) => unreachable!(),
1305     }
1306 }
1307 
write_atomnull1308 fn write_atom(out: &mut OutFile, atom: Atom) {
1309     match atom {
1310         Bool => write!(out, "bool"),
1311         Char => write!(out, "char"),
1312         U8 => write!(out, "::std::uint8_t"),
1313         U16 => write!(out, "::std::uint16_t"),
1314         U32 => write!(out, "::std::uint32_t"),
1315         U64 => write!(out, "::std::uint64_t"),
1316         Usize => write!(out, "::std::size_t"),
1317         I8 => write!(out, "::std::int8_t"),
1318         I16 => write!(out, "::std::int16_t"),
1319         I32 => write!(out, "::std::int32_t"),
1320         I64 => write!(out, "::std::int64_t"),
1321         Isize => write!(out, "::rust::isize"),
1322         F32 => write!(out, "float"),
1323         F64 => write!(out, "double"),
1324         CxxString => write!(out, "::std::string"),
1325         RustString => write!(out, "::rust::String"),
1326     }
1327 }
1328 
write_type_spacenull1329 fn write_type_space(out: &mut OutFile, ty: &Type) {
1330     write_type(out, ty);
1331     write_space_after_type(out, ty);
1332 }
1333 
write_space_after_typenull1334 fn write_space_after_type(out: &mut OutFile, ty: &Type) {
1335     match ty {
1336         Type::Ident(_)
1337         | Type::RustBox(_)
1338         | Type::UniquePtr(_)
1339         | Type::SharedPtr(_)
1340         | Type::WeakPtr(_)
1341         | Type::Str(_)
1342         | Type::CxxVector(_)
1343         | Type::RustVec(_)
1344         | Type::SliceRef(_)
1345         | Type::Fn(_)
1346         | Type::Array(_) => write!(out, " "),
1347         Type::Ref(_) | Type::Ptr(_) => {}
1348         Type::Void(_) => unreachable!(),
1349     }
1350 }
1351 
1352 #[derive(Copy, Clone)]
1353 enum UniquePtr<'a> {
1354     Ident(&'a Ident),
1355     CxxVector(&'a Ident),
1356 }
1357 
1358 trait ToTypename {
to_typenamenull1359     fn to_typename(&self, types: &Types) -> String;
1360 }
1361 
1362 impl ToTypename for Ident {
to_typenamenull1363     fn to_typename(&self, types: &Types) -> String {
1364         types.resolve(self).name.to_fully_qualified()
1365     }
1366 }
1367 
1368 impl<'a> ToTypename for UniquePtr<'a> {
to_typenamenull1369     fn to_typename(&self, types: &Types) -> String {
1370         match self {
1371             UniquePtr::Ident(ident) => ident.to_typename(types),
1372             UniquePtr::CxxVector(element) => {
1373                 format!("::std::vector<{}>", element.to_typename(types))
1374             }
1375         }
1376     }
1377 }
1378 
1379 trait ToMangled {
to_manglednull1380     fn to_mangled(&self, types: &Types) -> Symbol;
1381 }
1382 
1383 impl ToMangled for Ident {
to_manglednull1384     fn to_mangled(&self, types: &Types) -> Symbol {
1385         types.resolve(self).name.to_symbol()
1386     }
1387 }
1388 
1389 impl<'a> ToMangled for UniquePtr<'a> {
to_manglednull1390     fn to_mangled(&self, types: &Types) -> Symbol {
1391         match self {
1392             UniquePtr::Ident(ident) => ident.to_mangled(types),
1393             UniquePtr::CxxVector(element) => {
1394                 symbol::join(&[&"std", &"vector", &element.to_mangled(types)])
1395             }
1396         }
1397     }
1398 }
1399 
write_generic_instantiationsnull1400 fn write_generic_instantiations(out: &mut OutFile) {
1401     if out.header {
1402         return;
1403     }
1404 
1405     out.next_section();
1406     out.set_namespace(Default::default());
1407     out.begin_block(Block::ExternC);
1408     for impl_key in out.types.impls.keys() {
1409         out.next_section();
1410         match *impl_key {
1411             ImplKey::RustBox(ident) => write_rust_box_extern(out, ident),
1412             ImplKey::RustVec(ident) => write_rust_vec_extern(out, ident),
1413             ImplKey::UniquePtr(ident) => write_unique_ptr(out, ident),
1414             ImplKey::SharedPtr(ident) => write_shared_ptr(out, ident),
1415             ImplKey::WeakPtr(ident) => write_weak_ptr(out, ident),
1416             ImplKey::CxxVector(ident) => write_cxx_vector(out, ident),
1417         }
1418     }
1419     out.end_block(Block::ExternC);
1420 
1421     out.begin_block(Block::Namespace("rust"));
1422     out.begin_block(Block::InlineNamespace("cxxbridge1"));
1423     for impl_key in out.types.impls.keys() {
1424         match *impl_key {
1425             ImplKey::RustBox(ident) => write_rust_box_impl(out, ident),
1426             ImplKey::RustVec(ident) => write_rust_vec_impl(out, ident),
1427             _ => {}
1428         }
1429     }
1430     out.end_block(Block::InlineNamespace("cxxbridge1"));
1431     out.end_block(Block::Namespace("rust"));
1432 }
1433 
write_rust_box_externnull1434 fn write_rust_box_extern(out: &mut OutFile, key: NamedImplKey) {
1435     let resolve = out.types.resolve(&key);
1436     let inner = resolve.name.to_fully_qualified();
1437     let instance = resolve.name.to_symbol();
1438 
1439     writeln!(
1440         out,
1441         "{} *cxxbridge1$box${}$alloc() noexcept;",
1442         inner, instance,
1443     );
1444     writeln!(
1445         out,
1446         "void cxxbridge1$box${}$dealloc({} *) noexcept;",
1447         instance, inner,
1448     );
1449     writeln!(
1450         out,
1451         "void cxxbridge1$box${}$drop(::rust::Box<{}> *ptr) noexcept;",
1452         instance, inner,
1453     );
1454 }
1455 
write_rust_vec_externnull1456 fn write_rust_vec_extern(out: &mut OutFile, key: NamedImplKey) {
1457     let element = key.rust;
1458     let inner = element.to_typename(out.types);
1459     let instance = element.to_mangled(out.types);
1460 
1461     out.include.cstddef = true;
1462 
1463     writeln!(
1464         out,
1465         "void cxxbridge1$rust_vec${}$new(::rust::Vec<{}> const *ptr) noexcept;",
1466         instance, inner,
1467     );
1468     writeln!(
1469         out,
1470         "void cxxbridge1$rust_vec${}$drop(::rust::Vec<{}> *ptr) noexcept;",
1471         instance, inner,
1472     );
1473     writeln!(
1474         out,
1475         "::std::size_t cxxbridge1$rust_vec${}$len(::rust::Vec<{}> const *ptr) noexcept;",
1476         instance, inner,
1477     );
1478     writeln!(
1479         out,
1480         "::std::size_t cxxbridge1$rust_vec${}$capacity(::rust::Vec<{}> const *ptr) noexcept;",
1481         instance, inner,
1482     );
1483     writeln!(
1484         out,
1485         "{} const *cxxbridge1$rust_vec${}$data(::rust::Vec<{0}> const *ptr) noexcept;",
1486         inner, instance,
1487     );
1488     writeln!(
1489         out,
1490         "void cxxbridge1$rust_vec${}$reserve_total(::rust::Vec<{}> *ptr, ::std::size_t new_cap) noexcept;",
1491         instance, inner,
1492     );
1493     writeln!(
1494         out,
1495         "void cxxbridge1$rust_vec${}$set_len(::rust::Vec<{}> *ptr, ::std::size_t len) noexcept;",
1496         instance, inner,
1497     );
1498     writeln!(
1499         out,
1500         "void cxxbridge1$rust_vec${}$truncate(::rust::Vec<{}> *ptr, ::std::size_t len) noexcept;",
1501         instance, inner,
1502     );
1503 }
1504 
write_rust_box_implnull1505 fn write_rust_box_impl(out: &mut OutFile, key: NamedImplKey) {
1506     let resolve = out.types.resolve(&key);
1507     let inner = resolve.name.to_fully_qualified();
1508     let instance = resolve.name.to_symbol();
1509 
1510     writeln!(out, "template <>");
1511     begin_function_definition(out);
1512     writeln!(
1513         out,
1514         "{} *Box<{}>::allocation::alloc() noexcept {{",
1515         inner, inner,
1516     );
1517     writeln!(out, "  return cxxbridge1$box${}$alloc();", instance);
1518     writeln!(out, "}}");
1519 
1520     writeln!(out, "template <>");
1521     begin_function_definition(out);
1522     writeln!(
1523         out,
1524         "void Box<{}>::allocation::dealloc({} *ptr) noexcept {{",
1525         inner, inner,
1526     );
1527     writeln!(out, "  cxxbridge1$box${}$dealloc(ptr);", instance);
1528     writeln!(out, "}}");
1529 
1530     writeln!(out, "template <>");
1531     begin_function_definition(out);
1532     writeln!(out, "void Box<{}>::drop() noexcept {{", inner);
1533     writeln!(out, "  cxxbridge1$box${}$drop(this);", instance);
1534     writeln!(out, "}}");
1535 }
1536 
write_rust_vec_implnull1537 fn write_rust_vec_impl(out: &mut OutFile, key: NamedImplKey) {
1538     let element = key.rust;
1539     let inner = element.to_typename(out.types);
1540     let instance = element.to_mangled(out.types);
1541 
1542     out.include.cstddef = true;
1543 
1544     writeln!(out, "template <>");
1545     begin_function_definition(out);
1546     writeln!(out, "Vec<{}>::Vec() noexcept {{", inner);
1547     writeln!(out, "  cxxbridge1$rust_vec${}$new(this);", instance);
1548     writeln!(out, "}}");
1549 
1550     writeln!(out, "template <>");
1551     begin_function_definition(out);
1552     writeln!(out, "void Vec<{}>::drop() noexcept {{", inner);
1553     writeln!(out, "  return cxxbridge1$rust_vec${}$drop(this);", instance);
1554     writeln!(out, "}}");
1555 
1556     writeln!(out, "template <>");
1557     begin_function_definition(out);
1558     writeln!(
1559         out,
1560         "::std::size_t Vec<{}>::size() const noexcept {{",
1561         inner,
1562     );
1563     writeln!(out, "  return cxxbridge1$rust_vec${}$len(this);", instance);
1564     writeln!(out, "}}");
1565 
1566     writeln!(out, "template <>");
1567     begin_function_definition(out);
1568     writeln!(
1569         out,
1570         "::std::size_t Vec<{}>::capacity() const noexcept {{",
1571         inner,
1572     );
1573     writeln!(
1574         out,
1575         "  return cxxbridge1$rust_vec${}$capacity(this);",
1576         instance,
1577     );
1578     writeln!(out, "}}");
1579 
1580     writeln!(out, "template <>");
1581     begin_function_definition(out);
1582     writeln!(out, "{} const *Vec<{0}>::data() const noexcept {{", inner);
1583     writeln!(out, "  return cxxbridge1$rust_vec${}$data(this);", instance);
1584     writeln!(out, "}}");
1585 
1586     writeln!(out, "template <>");
1587     begin_function_definition(out);
1588     writeln!(
1589         out,
1590         "void Vec<{}>::reserve_total(::std::size_t new_cap) noexcept {{",
1591         inner,
1592     );
1593     writeln!(
1594         out,
1595         "  return cxxbridge1$rust_vec${}$reserve_total(this, new_cap);",
1596         instance,
1597     );
1598     writeln!(out, "}}");
1599 
1600     writeln!(out, "template <>");
1601     begin_function_definition(out);
1602     writeln!(
1603         out,
1604         "void Vec<{}>::set_len(::std::size_t len) noexcept {{",
1605         inner,
1606     );
1607     writeln!(
1608         out,
1609         "  return cxxbridge1$rust_vec${}$set_len(this, len);",
1610         instance,
1611     );
1612     writeln!(out, "}}");
1613 
1614     writeln!(out, "template <>");
1615     begin_function_definition(out);
1616     writeln!(out, "void Vec<{}>::truncate(::std::size_t len) {{", inner,);
1617     writeln!(
1618         out,
1619         "  return cxxbridge1$rust_vec${}$truncate(this, len);",
1620         instance,
1621     );
1622     writeln!(out, "}}");
1623 }
1624 
write_unique_ptrnull1625 fn write_unique_ptr(out: &mut OutFile, key: NamedImplKey) {
1626     let ty = UniquePtr::Ident(key.rust);
1627     write_unique_ptr_common(out, ty);
1628 }
1629 
1630 // Shared by UniquePtr<T> and UniquePtr<CxxVector<T>>.
write_unique_ptr_commonnull1631 fn write_unique_ptr_common(out: &mut OutFile, ty: UniquePtr) {
1632     out.include.new = true;
1633     out.include.utility = true;
1634     let inner = ty.to_typename(out.types);
1635     let instance = ty.to_mangled(out.types);
1636 
1637     let can_construct_from_value = match ty {
1638         // Some aliases are to opaque types; some are to trivial types. We can't
1639         // know at code generation time, so we generate both C++ and Rust side
1640         // bindings for a "new" method anyway. But the Rust code can't be called
1641         // for Opaque types because the 'new' method is not implemented.
1642         UniquePtr::Ident(ident) => out.types.is_maybe_trivial(ident),
1643         UniquePtr::CxxVector(_) => false,
1644     };
1645 
1646     let conditional_delete = match ty {
1647         UniquePtr::Ident(ident) => {
1648             !out.types.structs.contains_key(ident) && !out.types.enums.contains_key(ident)
1649         }
1650         UniquePtr::CxxVector(_) => false,
1651     };
1652 
1653     if conditional_delete {
1654         out.builtin.is_complete = true;
1655         let definition = match ty {
1656             UniquePtr::Ident(ty) => &out.types.resolve(ty).name.cxx,
1657             UniquePtr::CxxVector(_) => unreachable!(),
1658         };
1659         writeln!(
1660             out,
1661             "static_assert(::rust::detail::is_complete<{}>::value, \"definition of {} is required\");",
1662             inner, definition,
1663         );
1664     }
1665     writeln!(
1666         out,
1667         "static_assert(sizeof(::std::unique_ptr<{}>) == sizeof(void *), \"\");",
1668         inner,
1669     );
1670     writeln!(
1671         out,
1672         "static_assert(alignof(::std::unique_ptr<{}>) == alignof(void *), \"\");",
1673         inner,
1674     );
1675     begin_function_definition(out);
1676     writeln!(
1677         out,
1678         "void cxxbridge1$unique_ptr${}$null(::std::unique_ptr<{}> *ptr) noexcept {{",
1679         instance, inner,
1680     );
1681     writeln!(out, "  ::new (ptr) ::std::unique_ptr<{}>();", inner);
1682     writeln!(out, "}}");
1683     if can_construct_from_value {
1684         out.builtin.maybe_uninit = true;
1685         begin_function_definition(out);
1686         writeln!(
1687             out,
1688             "{} *cxxbridge1$unique_ptr${}$uninit(::std::unique_ptr<{}> *ptr) noexcept {{",
1689             inner, instance, inner,
1690         );
1691         writeln!(
1692             out,
1693             "  {} *uninit = reinterpret_cast<{} *>(new ::rust::MaybeUninit<{}>);",
1694             inner, inner, inner,
1695         );
1696         writeln!(out, "  ::new (ptr) ::std::unique_ptr<{}>(uninit);", inner);
1697         writeln!(out, "  return uninit;");
1698         writeln!(out, "}}");
1699     }
1700     begin_function_definition(out);
1701     writeln!(
1702         out,
1703         "void cxxbridge1$unique_ptr${}$raw(::std::unique_ptr<{}> *ptr, {} *raw) noexcept {{",
1704         instance, inner, inner,
1705     );
1706     writeln!(out, "  ::new (ptr) ::std::unique_ptr<{}>(raw);", inner);
1707     writeln!(out, "}}");
1708     begin_function_definition(out);
1709     writeln!(
1710         out,
1711         "{} const *cxxbridge1$unique_ptr${}$get(::std::unique_ptr<{}> const &ptr) noexcept {{",
1712         inner, instance, inner,
1713     );
1714     writeln!(out, "  return ptr.get();");
1715     writeln!(out, "}}");
1716     begin_function_definition(out);
1717     writeln!(
1718         out,
1719         "{} *cxxbridge1$unique_ptr${}$release(::std::unique_ptr<{}> &ptr) noexcept {{",
1720         inner, instance, inner,
1721     );
1722     writeln!(out, "  return ptr.release();");
1723     writeln!(out, "}}");
1724     begin_function_definition(out);
1725     writeln!(
1726         out,
1727         "void cxxbridge1$unique_ptr${}$drop(::std::unique_ptr<{}> *ptr) noexcept {{",
1728         instance, inner,
1729     );
1730     if conditional_delete {
1731         out.builtin.deleter_if = true;
1732         writeln!(
1733             out,
1734             "  ::rust::deleter_if<::rust::detail::is_complete<{}>::value>{{}}(ptr);",
1735             inner,
1736         );
1737     } else {
1738         writeln!(out, "  ptr->~unique_ptr();");
1739     }
1740     writeln!(out, "}}");
1741 }
1742 
write_shared_ptrnull1743 fn write_shared_ptr(out: &mut OutFile, key: NamedImplKey) {
1744     let ident = key.rust;
1745     let resolve = out.types.resolve(ident);
1746     let inner = resolve.name.to_fully_qualified();
1747     let instance = resolve.name.to_symbol();
1748 
1749     out.include.new = true;
1750     out.include.utility = true;
1751 
1752     // Some aliases are to opaque types; some are to trivial types. We can't
1753     // know at code generation time, so we generate both C++ and Rust side
1754     // bindings for a "new" method anyway. But the Rust code can't be called for
1755     // Opaque types because the 'new' method is not implemented.
1756     let can_construct_from_value = out.types.is_maybe_trivial(ident);
1757 
1758     writeln!(
1759         out,
1760         "static_assert(sizeof(::std::shared_ptr<{}>) == 2 * sizeof(void *), \"\");",
1761         inner,
1762     );
1763     writeln!(
1764         out,
1765         "static_assert(alignof(::std::shared_ptr<{}>) == alignof(void *), \"\");",
1766         inner,
1767     );
1768     begin_function_definition(out);
1769     writeln!(
1770         out,
1771         "void cxxbridge1$shared_ptr${}$null(::std::shared_ptr<{}> *ptr) noexcept {{",
1772         instance, inner,
1773     );
1774     writeln!(out, "  ::new (ptr) ::std::shared_ptr<{}>();", inner);
1775     writeln!(out, "}}");
1776     if can_construct_from_value {
1777         out.builtin.maybe_uninit = true;
1778         begin_function_definition(out);
1779         writeln!(
1780             out,
1781             "{} *cxxbridge1$shared_ptr${}$uninit(::std::shared_ptr<{}> *ptr) noexcept {{",
1782             inner, instance, inner,
1783         );
1784         writeln!(
1785             out,
1786             "  {} *uninit = reinterpret_cast<{} *>(new ::rust::MaybeUninit<{}>);",
1787             inner, inner, inner,
1788         );
1789         writeln!(out, "  ::new (ptr) ::std::shared_ptr<{}>(uninit);", inner);
1790         writeln!(out, "  return uninit;");
1791         writeln!(out, "}}");
1792     }
1793     begin_function_definition(out);
1794     writeln!(
1795         out,
1796         "void cxxbridge1$shared_ptr${}$clone(::std::shared_ptr<{}> const &self, ::std::shared_ptr<{}> *ptr) noexcept {{",
1797         instance, inner, inner,
1798     );
1799     writeln!(out, "  ::new (ptr) ::std::shared_ptr<{}>(self);", inner);
1800     writeln!(out, "}}");
1801     begin_function_definition(out);
1802     writeln!(
1803         out,
1804         "{} const *cxxbridge1$shared_ptr${}$get(::std::shared_ptr<{}> const &self) noexcept {{",
1805         inner, instance, inner,
1806     );
1807     writeln!(out, "  return self.get();");
1808     writeln!(out, "}}");
1809     begin_function_definition(out);
1810     writeln!(
1811         out,
1812         "void cxxbridge1$shared_ptr${}$drop(::std::shared_ptr<{}> *self) noexcept {{",
1813         instance, inner,
1814     );
1815     writeln!(out, "  self->~shared_ptr();");
1816     writeln!(out, "}}");
1817 }
1818 
write_weak_ptrnull1819 fn write_weak_ptr(out: &mut OutFile, key: NamedImplKey) {
1820     let resolve = out.types.resolve(&key);
1821     let inner = resolve.name.to_fully_qualified();
1822     let instance = resolve.name.to_symbol();
1823 
1824     out.include.new = true;
1825     out.include.utility = true;
1826 
1827     writeln!(
1828         out,
1829         "static_assert(sizeof(::std::weak_ptr<{}>) == 2 * sizeof(void *), \"\");",
1830         inner,
1831     );
1832     writeln!(
1833         out,
1834         "static_assert(alignof(::std::weak_ptr<{}>) == alignof(void *), \"\");",
1835         inner,
1836     );
1837     writeln!(
1838         out,
1839         "void cxxbridge1$weak_ptr${}$null(::std::weak_ptr<{}> *ptr) noexcept {{",
1840         instance, inner,
1841     );
1842     writeln!(out, "  ::new (ptr) ::std::weak_ptr<{}>();", inner);
1843     writeln!(out, "}}");
1844     begin_function_definition(out);
1845     writeln!(
1846         out,
1847         "void cxxbridge1$weak_ptr${}$clone(::std::weak_ptr<{}> const &self, ::std::weak_ptr<{}> *ptr) noexcept {{",
1848         instance, inner, inner,
1849     );
1850     writeln!(out, "  ::new (ptr) ::std::weak_ptr<{}>(self);", inner);
1851     writeln!(out, "}}");
1852     begin_function_definition(out);
1853     writeln!(
1854         out,
1855         "void cxxbridge1$weak_ptr${}$downgrade(::std::shared_ptr<{}> const &shared, ::std::weak_ptr<{}> *weak) noexcept {{",
1856         instance, inner, inner,
1857     );
1858     writeln!(out, "  ::new (weak) ::std::weak_ptr<{}>(shared);", inner);
1859     writeln!(out, "}}");
1860     begin_function_definition(out);
1861     writeln!(
1862         out,
1863         "void cxxbridge1$weak_ptr${}$upgrade(::std::weak_ptr<{}> const &weak, ::std::shared_ptr<{}> *shared) noexcept {{",
1864         instance, inner, inner,
1865     );
1866     writeln!(
1867         out,
1868         "  ::new (shared) ::std::shared_ptr<{}>(weak.lock());",
1869         inner,
1870     );
1871     writeln!(out, "}}");
1872     begin_function_definition(out);
1873     writeln!(
1874         out,
1875         "void cxxbridge1$weak_ptr${}$drop(::std::weak_ptr<{}> *self) noexcept {{",
1876         instance, inner,
1877     );
1878     writeln!(out, "  self->~weak_ptr();");
1879     writeln!(out, "}}");
1880 }
1881 
write_cxx_vectornull1882 fn write_cxx_vector(out: &mut OutFile, key: NamedImplKey) {
1883     let element = key.rust;
1884     let inner = element.to_typename(out.types);
1885     let instance = element.to_mangled(out.types);
1886 
1887     out.include.cstddef = true;
1888     out.include.utility = true;
1889     out.builtin.destroy = true;
1890 
1891     writeln!(
1892         out,
1893         "::std::size_t cxxbridge1$std$vector${}$size(::std::vector<{}> const &s) noexcept {{",
1894         instance, inner,
1895     );
1896     writeln!(out, "  return s.size();");
1897     writeln!(out, "}}");
1898 
1899     begin_function_definition(out);
1900     writeln!(
1901         out,
1902         "{} *cxxbridge1$std$vector${}$get_unchecked(::std::vector<{}> *s, ::std::size_t pos) noexcept {{",
1903         inner, instance, inner,
1904     );
1905     writeln!(out, "  return &(*s)[pos];");
1906     writeln!(out, "}}");
1907 
1908     if out.types.is_maybe_trivial(element) {
1909         begin_function_definition(out);
1910         writeln!(
1911             out,
1912             "void cxxbridge1$std$vector${}$push_back(::std::vector<{}> *v, {} *value) noexcept {{",
1913             instance, inner, inner,
1914         );
1915         writeln!(out, "  v->push_back(::std::move(*value));");
1916         writeln!(out, "  ::rust::destroy(value);");
1917         writeln!(out, "}}");
1918 
1919         begin_function_definition(out);
1920         writeln!(
1921             out,
1922             "void cxxbridge1$std$vector${}$pop_back(::std::vector<{}> *v, {} *out) noexcept {{",
1923             instance, inner, inner,
1924         );
1925         writeln!(out, "  ::new (out) {}(::std::move(v->back()));", inner);
1926         writeln!(out, "  v->pop_back();");
1927         writeln!(out, "}}");
1928     }
1929 
1930     out.include.memory = true;
1931     write_unique_ptr_common(out, UniquePtr::CxxVector(element));
1932 }
1933