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