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