cxx_gen/gen/
write.rs

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