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