cxx_build/gen/
write.rs

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