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