1use std::{
2 collections::HashMap,
3 fmt::{Display, Write},
4 iter,
5};
6
7use itertools::Itertools;
8use zngur_def::{CppRef, CppValue, Mutability, RustTrait, ZngurField, ZngurMethodReceiver};
9
10use crate::{ZngurWellknownTraitData, rust::IntoCpp};
11
12#[derive(Debug)]
13pub struct CppPath(pub Vec<String>);
14
15impl CppPath {
16 fn namespace(&self) -> &[String] {
17 self.0.split_last().unwrap().1
18 }
19
20 fn emit_in_namespace(
21 &self,
22 state: &mut State,
23 f: impl FnOnce(&mut State) -> std::fmt::Result,
24 ) -> std::fmt::Result {
25 for p in self.namespace() {
26 writeln!(state, "namespace {} {{", p)?;
27 }
28 f(state)?;
29 for _ in self.namespace() {
30 writeln!(state, "}}")?;
31 }
32 Ok(())
33 }
34
35 fn name(&self) -> &str {
36 self.0.split_last().unwrap().0
37 }
38
39 fn need_header(&self) -> bool {
40 self.0.first().map(|x| x.as_str()) == Some("rust")
41 && self.0 != ["rust", "Unit"]
42 && self.0 != ["rust", "Ref"]
43 && self.0 != ["rust", "RefMut"]
44 }
45
46 pub(crate) fn from_rust_path(path: &[String]) -> CppPath {
47 CppPath(
48 iter::once("rust")
49 .chain(path.iter().map(|x| x.as_str()))
50 .map(cpp_handle_keyword)
51 .map(|x| x.to_owned())
52 .collect(),
53 )
54 }
55}
56
57impl<const N: usize> From<[&str; N]> for CppPath {
58 fn from(value: [&str; N]) -> Self {
59 CppPath(value.iter().map(|x| x.to_string()).collect())
60 }
61}
62
63impl From<&str> for CppPath {
64 fn from(value: &str) -> Self {
65 let value = value.trim();
66 CppPath(value.split("::").map(|x| x.to_owned()).collect())
67 }
68}
69
70impl Display for CppPath {
71 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
72 write!(f, "::{}", self.0.iter().join("::"))
73 }
74}
75
76#[derive(Debug)]
77pub struct CppType {
78 pub path: CppPath,
79 pub generic_args: Vec<CppType>,
80}
81
82impl CppType {
83 pub fn into_ref(self) -> CppType {
84 CppType {
85 path: CppPath::from("rust::Ref"),
86 generic_args: vec![self],
87 }
88 }
89
90 fn emit_specialization_decl(&self, state: &mut State) -> std::fmt::Result {
91 if self.generic_args.is_empty() {
92 write!(state, "struct {}", self.path.name())?;
93 } else {
94 write!(
95 state,
96 "template<> struct {}< {} >",
97 self.path.name(),
98 self.generic_args.iter().join(", ")
99 )?;
100 }
101 Ok(())
102 }
103
104 fn emit_header(&self, state: &mut State) -> std::fmt::Result {
105 for x in &self.generic_args {
106 x.emit_header(state)?;
107 }
108 if !self.path.need_header() {
109 return Ok(());
110 }
111 self.path.emit_in_namespace(state, |state| {
112 if !self.generic_args.is_empty() {
113 writeln!(state, "template<typename ...T>")?;
114 }
115 writeln!(state, "struct {};", self.path.name())
116 })
117 }
118}
119
120impl Display for CppType {
121 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
122 write!(f, "{}", self.path)?;
123 if !self.generic_args.is_empty() {
124 write!(f, "< {} >", self.generic_args.iter().join(", "))?;
125 }
126 Ok(())
127 }
128}
129
130fn split_string(input: &str) -> impl Iterator<Item = String> {
131 let mut parts = Vec::new();
132 let mut current_part = String::new();
133 let mut parentheses_count = 0;
134
135 for c in input.chars() {
136 match c {
137 ',' if parentheses_count == 0 => {
138 parts.push(current_part.clone());
139 current_part.clear();
140 }
141 '<' => {
142 parentheses_count += 1;
143 current_part.push(c);
144 }
145 '>' => {
146 parentheses_count -= 1;
147 current_part.push(c);
148 }
149 _ => {
150 current_part.push(c);
151 }
152 }
153 }
154
155 if !current_part.is_empty() {
156 parts.push(current_part);
157 }
158
159 parts.into_iter()
160}
161
162impl From<&str> for CppType {
163 fn from(value: &str) -> Self {
164 let value = value.trim();
165 match value.split_once('<') {
166 None => CppType {
167 path: CppPath::from(value),
168 generic_args: vec![],
169 },
170 Some((path, generics)) => {
171 let generics = generics.strip_suffix('>').unwrap();
172 CppType {
173 path: CppPath::from(path),
174 generic_args: split_string(generics).map(|x| CppType::from(&*x)).collect(),
175 }
176 }
177 }
178 }
179}
180
181struct State {
182 text: String,
183 panic_to_exception: bool,
184}
185
186impl State {
187 fn panic_handler(&self) -> String {
188 if self.panic_to_exception {
189 r#"
190 if (__zngur_detect_panic()) {
191 __zngur_take_panic();
192 throw ::rust::Panic{};
193 }
194 "#
195 .to_owned()
196 } else {
197 "".to_owned()
198 }
199 }
200
201 fn remove_no_except_in_panic(&mut self) {
202 if self.panic_to_exception {
203 self.text = self.text.replace(" noexcept ", " ");
204 }
205 }
206}
207
208impl Write for State {
209 fn write_str(&mut self, s: &str) -> std::fmt::Result {
210 self.text += s;
211 Ok(())
212 }
213}
214
215#[derive(Debug)]
216pub struct CppTraitMethod {
217 pub name: String,
218 pub rust_link_name: String,
219 pub inputs: Vec<CppType>,
220 pub output: CppType,
221}
222
223#[derive(Debug)]
224pub struct CppFnSig {
225 pub rust_link_name: String,
226 pub inputs: Vec<CppType>,
227 pub output: CppType,
228}
229
230impl CppFnSig {
231 fn emit_rust_link(&self, state: &mut State) -> std::fmt::Result {
232 write!(state, "void {}(", self.rust_link_name)?;
233 for n in 0..self.inputs.len() {
234 write!(state, "uint8_t* i{n},")?;
235 }
236 write!(state, "uint8_t* o)")?;
237 Ok(())
238 }
239
240 fn emit_rust_link_decl(&self, state: &mut State) -> std::fmt::Result {
241 self.emit_rust_link(state)?;
242 writeln!(state, " noexcept ;")?;
243 Ok(())
244 }
245
246 fn emit_cpp_header(&self, state: &mut State, fn_name: &str) -> std::fmt::Result {
247 let CppFnSig {
248 inputs,
249 output,
250 rust_link_name: _,
251 } = self;
252 writeln!(
253 state,
254 "{output} {fn_name}({input_defs}) noexcept ;",
255 input_defs = inputs
256 .iter()
257 .enumerate()
258 .map(|(n, ty)| format!("{ty} i{n}"))
259 .join(", "),
260 )
261 }
262
263 fn emit_cpp_def(&self, state: &mut State, fn_name: &str) -> std::fmt::Result {
264 let CppFnSig {
265 inputs,
266 output,
267 rust_link_name,
268 } = self;
269 writeln!(
270 state,
271 "inline {output} {fn_name}({input_defs}) noexcept {{
272 {output} o{{}};
273 {deinits}
274 {rust_link_name}({input_args}::rust::__zngur_internal_data_ptr(o));
275 {panic_handler}
276 ::rust::__zngur_internal_assume_init(o);
277 return o;
278 }}",
279 input_defs = inputs
280 .iter()
281 .enumerate()
282 .map(|(n, ty)| format!("{ty} i{n}"))
283 .join(", "),
284 input_args = (0..inputs.len())
285 .map(|n| format!("::rust::__zngur_internal_data_ptr(i{n}), "))
286 .join(""),
287 panic_handler = state.panic_handler(),
288 deinits = (0..inputs.len())
289 .map(|n| format!("::rust::__zngur_internal_assume_deinit(i{n});"))
290 .join("\n"),
291 )
292 }
293}
294
295pub struct CppFnDefinition {
296 pub name: CppPath,
297 pub sig: CppFnSig,
298}
299
300pub struct CppExportedFnDefinition {
301 pub name: String,
302 pub sig: CppFnSig,
303}
304
305pub struct CppExportedImplDefinition {
306 pub tr: Option<CppType>,
307 pub ty: CppType,
308 pub methods: Vec<(String, CppFnSig)>,
309}
310
311impl CppFnDefinition {
312 fn emit_cpp_def(&self, state: &mut State) -> std::fmt::Result {
313 self.name.emit_in_namespace(state, |state| {
314 self.sig.emit_cpp_def(state, self.name.name())
315 })
316 }
317}
318
319#[derive(Debug)]
320pub struct CppMethod {
321 pub name: String,
322 pub kind: ZngurMethodReceiver,
323 pub sig: CppFnSig,
324}
325
326#[derive(Debug)]
327pub struct BuildFromFunction {
328 pub sig: CppFnSig,
329}
330
331#[derive(Debug)]
332pub enum CppTraitDefinition {
333 Fn {
334 sig: CppFnSig,
335 },
336 Normal {
337 as_ty: CppType,
338 methods: Vec<CppTraitMethod>,
339 link_name: String,
340 link_name_ref: String,
341 },
342}
343
344impl CppTraitDefinition {
345 fn emit_rust_links(&self, state: &mut State) -> std::fmt::Result {
346 match self {
347 CppTraitDefinition::Fn {
348 sig:
349 CppFnSig {
350 rust_link_name,
351 inputs,
352 output: _,
353 },
354 } => {
355 writeln!(
356 state,
357 "void {rust_link_name}(uint8_t *data, void destructor(uint8_t *),
358 void call(uint8_t *, {} uint8_t *),
359 uint8_t *o);",
360 (0..inputs.len()).map(|_| "uint8_t *, ").join(" ")
361 )?;
362 }
363 CppTraitDefinition::Normal {
364 link_name,
365 link_name_ref,
366 ..
367 } => {
368 writeln!(
369 state,
370 "void {link_name}(uint8_t *data, void destructor(uint8_t *), uint8_t *o);"
371 )?;
372 writeln!(state, "void {link_name_ref}(uint8_t *data, uint8_t *o);")?;
373 }
374 }
375 Ok(())
376 }
377
378 fn emit(&self, state: &mut State) -> std::fmt::Result {
379 let CppTraitDefinition::Normal {
380 as_ty,
381 methods,
382 link_name: _,
383 link_name_ref: _,
384 } = self
385 else {
386 return Ok(());
387 };
388 as_ty.path.emit_in_namespace(state, |state| {
389 as_ty.emit_specialization_decl(state)?;
390 write!(
391 state,
392 r#"{{
393 public:
394 virtual ~{}() {{}}
395 "#,
396 as_ty.path.name(),
397 )?;
398 for method in methods {
399 write!(
400 state,
401 r#"
402 virtual {output} {name}({input}) = 0;
403 "#,
404 output = method.output,
405 name = method.name,
406 input = method
407 .inputs
408 .iter()
409 .enumerate()
410 .map(|(n, x)| format!("{x} i{n}"))
411 .join(", "),
412 )?;
413 }
414 write!(
415 state,
416 r#"
417 }};
418 "#,
419 )
420 })
421 }
422
423 fn emit_cpp(&self, state: &mut State) -> std::fmt::Result {
424 match self {
425 CppTraitDefinition::Fn { .. } => (),
426 CppTraitDefinition::Normal {
427 as_ty,
428 methods,
429 link_name: _,
430 link_name_ref: _,
431 } => {
432 for method in methods {
433 write!(state, "void {}(uint8_t* data", method.rust_link_name)?;
434 for arg in 0..method.inputs.len() {
435 write!(state, ", uint8_t* i{arg}")?;
436 }
437 writeln!(state, ", uint8_t* o) {{")?;
438 writeln!(
439 state,
440 " {as_ty}* data_typed = reinterpret_cast< {as_ty}* >(data);"
441 )?;
442 write!(
443 state,
444 " {} oo = data_typed->{}({});",
445 method.output,
446 method.name,
447 method
448 .inputs
449 .iter()
450 .enumerate()
451 .map(|(n, ty)| {
452 format!("::rust::__zngur_internal_move_from_rust< {ty} >(i{n})")
453 })
454 .join(", ")
455 )?;
456 writeln!(state, " ::rust::__zngur_internal_move_to_rust(o, oo);")?;
457 writeln!(state, "}}")?;
458 }
459 }
460 }
461 Ok(())
462 }
463}
464
465#[derive(Debug, Clone, PartialEq, Eq)]
466pub enum CppLayoutPolicy {
467 StackAllocated {
468 size: usize,
469 align: usize,
470 },
471 HeapAllocated {
472 size_fn: String,
473 alloc_fn: String,
474 free_fn: String,
475 },
476 OnlyByRef,
477}
478
479#[derive(Debug)]
480pub struct CppTypeDefinition {
481 pub ty: CppType,
482 pub layout: CppLayoutPolicy,
483 pub methods: Vec<CppMethod>,
484 pub constructors: Vec<CppFnSig>,
485 pub fields: Vec<ZngurField>,
486 pub from_trait: Option<RustTrait>,
487 pub from_trait_ref: Option<RustTrait>,
488 pub wellknown_traits: Vec<ZngurWellknownTraitData>,
489 pub cpp_value: Option<CppValue>,
490 pub cpp_ref: Option<CppRef>,
491}
492
493impl Default for CppTypeDefinition {
494 fn default() -> Self {
495 Self {
496 ty: CppType::from("fill::me::you::forgot::it"),
497 layout: CppLayoutPolicy::OnlyByRef,
498 methods: vec![],
499 constructors: vec![],
500 fields: vec![],
501 wellknown_traits: vec![],
502 from_trait: None,
503 from_trait_ref: None,
504 cpp_value: None,
505 cpp_ref: None,
506 }
507 }
508}
509
510impl CppTypeDefinition {
511 fn emit_field_specialization(&self, state: &mut State) -> std::fmt::Result {
512 for field_kind in ["FieldOwned", "FieldRef", "FieldRefMut"] {
513 writeln!(
514 state,
515 r#"
516 namespace rust {{
517 template<size_t OFFSET>
518 struct {field_kind}< {ty}, OFFSET > {{
519 "#,
520 ty = self.ty,
521 )?;
522 for field in &self.fields {
523 writeln!(
524 state,
525 "[[no_unique_address]] {field_kind}<{}, OFFSET + {}> {};",
526 field.ty.into_cpp(),
527 field.offset,
528 cpp_handle_field_name(&field.name),
529 )?;
530 }
531 for method in &self.methods {
532 if let ZngurMethodReceiver::Ref(m) = method.kind {
533 if m == Mutability::Mut && field_kind == "FieldRef" {
534 continue;
535 }
536 let CppFnSig {
537 rust_link_name: _,
538 inputs,
539 output,
540 } = &method.sig;
541 writeln!(
542 state,
543 "{output} {fn_name}({input_defs}) const noexcept ;",
544 fn_name = &method.name,
545 input_defs = inputs
546 .iter()
547 .skip(1)
548 .enumerate()
549 .map(|(n, ty)| format!("{ty} i{n}"))
550 .join(", "),
551 )?;
552 }
553 }
554 writeln!(state, "}};\n}}")?;
555 }
556 Ok(())
557 }
558
559 fn emit_ref_specialization(&self, state: &mut State) -> std::fmt::Result {
560 for ref_kind in ["RefMut", "Ref"] {
561 let is_unsized = self
562 .wellknown_traits
563 .contains(&ZngurWellknownTraitData::Unsized);
564 if self.ty.path.to_string() == "::rust::Str" && ref_kind == "Ref" {
565 writeln!(
566 state,
567 r#"
568 auto operator""_rs(const char* input, size_t len) -> ::rust::Ref<::rust::Str>;
569"#,
570 )?;
571 }
572 if is_unsized {
573 writeln!(
574 state,
575 r#"
576namespace rust {{
577template<>
578struct {ref_kind}< {ty} > {{
579 {ref_kind}() {{
580 data = {{0, 0}};
581 }}
582private:
583 ::std::array<size_t, 2> data;
584 friend uint8_t* ::rust::__zngur_internal_data_ptr< ::rust::{ref_kind}< {ty} > >(const ::rust::{ref_kind}< {ty} >& t) noexcept ;
585 friend ::rust::ZngurPrettyPrinter< ::rust::{ref_kind}< {ty} > >;
586"#,
587 ty = self.ty,
588 )?;
589 } else {
590 writeln!(
591 state,
592 r#"
593namespace rust {{
594template<>
595struct {ref_kind}< {ty} > {{
596 {ref_kind}() {{
597 data = 0;
598 }}
599"#,
600 ty = self.ty,
601 )?;
602 if !matches!(self.layout, CppLayoutPolicy::OnlyByRef) {
603 writeln!(
604 state,
605 r#"
606 {ref_kind}(const {ty}& t) {{
607 ::rust::__zngur_internal_check_init< {ty} >(t);
608 data = reinterpret_cast<size_t>(__zngur_internal_data_ptr(t));
609 }}
610"#,
611 ty = self.ty,
612 )?;
613 }
614 for field in &self.fields {
615 writeln!(
616 state,
617 "[[no_unique_address]] ::rust::Field{ref_kind}<{}, {}> {};",
618 field.ty.into_cpp(),
619 field.offset,
620 cpp_handle_field_name(&field.name),
621 )?;
622 }
623 writeln!(
624 state,
625 r#"
626private:
627 size_t data;
628 friend uint8_t* ::rust::__zngur_internal_data_ptr< ::rust::{ref_kind}< {ty} > >(const ::rust::{ref_kind}< {ty} >& t) noexcept ;
629 friend ::rust::ZngurPrettyPrinter< ::rust::{ref_kind}< {ty} > >;
630"#,
631 ty = self.ty,
632 )?;
633 }
634 writeln!(state, "public:")?;
635 if ref_kind == "Ref" {
636 writeln!(
637 state,
638 r#"
639 Ref(RefMut< {ty} > rm) {{
640 data = rm.data;
641 }}
642 "#,
643 ty = self.ty,
644 )?;
645 if !is_unsized {
646 writeln!(
647 state,
648 r#"
649 template<size_t OFFSET>
650 Ref(const FieldOwned< {ty}, OFFSET >& f) {{
651 data = reinterpret_cast<size_t>(&f) + OFFSET;
652 }}
653
654 template<size_t OFFSET>
655 Ref(const FieldRef< {ty}, OFFSET >& f) {{
656 data = *reinterpret_cast<const size_t*>(&f) + OFFSET;
657 }}
658
659 template<size_t OFFSET>
660 Ref(const FieldRefMut< {ty}, OFFSET >& f) {{
661 data = *reinterpret_cast<const size_t*>(&f) + OFFSET;
662 }}
663 "#,
664 ty = self.ty,
665 )?;
666 }
667 } else {
668 writeln!(
669 state,
670 r#"
671 friend Ref< {ty} >;
672 "#,
673 ty = self.ty,
674 )?;
675 if !is_unsized {
676 writeln!(
677 state,
678 r#"
679 template<size_t OFFSET>
680 RefMut(const FieldOwned< {ty}, OFFSET >& f) {{
681 data = reinterpret_cast<size_t>(&f) + OFFSET;
682 }}
683
684 template<size_t OFFSET>
685 RefMut(const FieldRefMut< {ty}, OFFSET >& f) {{
686 data = *reinterpret_cast<const size_t*>(&f) + OFFSET;
687 }}
688 "#,
689 ty = self.ty,
690 )?;
691 }
692 }
693 match &self.from_trait_ref {
694 Some(RustTrait::Fn { inputs, output, .. }) => {
695 let as_std_function = format!(
696 "::std::function< {}({})>",
697 output.into_cpp(),
698 inputs.iter().map(|x| x.into_cpp()).join(", ")
699 );
700 writeln!(
701 state,
702 r#"
703inline {ty}({as_std_function} f);
704"#,
705 ty = self.ty.path.name(),
706 )?;
707 }
708 Some(tr @ RustTrait::Normal { .. }) => {
709 let tr = tr.into_cpp();
710 writeln!(
711 state,
712 r#"
713 inline {ref_kind}({tr}& arg);
714 "#,
715 )?;
716 }
717 None => (),
718 }
719 if let Some(CppValue(rust_link_name, cpp_ty)) = &self.cpp_value {
720 writeln!(
721 state,
722 r#"
723 inline {cpp_ty}& cpp() {{
724 return (*{rust_link_name}(reinterpret_cast<uint8_t*>(data))).as_cpp< {cpp_ty} >();
725 }}"#
726 )?;
727 }
728 if let Some(cpp_ty) = &self.cpp_ref {
729 writeln!(
730 state,
731 r#"
732 inline {cpp_ty}& cpp() {{
733 return *reinterpret_cast< {cpp_ty}* >(data);
734 }}"#
735 )?;
736 writeln!(
737 state,
738 r#"
739 inline {ref_kind}(const {cpp_ty}& t) : data(reinterpret_cast<size_t>(&t)) {{}}"#
740 )?;
741 }
742 for method in &self.methods {
743 if let ZngurMethodReceiver::Ref(m) = method.kind {
744 if m == Mutability::Mut && ref_kind == "Ref" {
745 continue;
746 }
747 let CppFnSig {
748 rust_link_name: _,
749 inputs,
750 output,
751 } = &method.sig;
752 writeln!(
753 state,
754 "{output} {fn_name}({input_defs}) const noexcept ;",
755 fn_name = &method.name,
756 input_defs = inputs
757 .iter()
758 .skip(1)
759 .enumerate()
760 .map(|(n, ty)| format!("{ty} i{n}"))
761 .join(", "),
762 )?;
763 }
764 }
765 if self.ty.path.to_string() == "::rust::Str" && ref_kind == "Ref" {
766 writeln!(
767 state,
768 r#"
769 friend auto ::operator""_rs(const char* input, size_t len) -> ::rust::Ref<::rust::Str>;
770}};
771"#,
772 )?;
773 } else {
774 writeln!(state, "}};")?;
775 }
776 writeln!(
777 state,
778 r#"
779template<>
780inline uint8_t* __zngur_internal_data_ptr< {ref_kind} < {ty} > >(const {ref_kind}< {ty} >& t) noexcept {{
781 return const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(&t.data));
782}}
783
784template<>
785inline void __zngur_internal_assume_init< {ref_kind} < {ty} > >({ref_kind}< {ty} >&) noexcept {{
786}}
787
788template<>
789inline void __zngur_internal_check_init< {ref_kind} < {ty} > >(const {ref_kind}< {ty} >&) noexcept {{
790}}
791
792template<>
793inline void __zngur_internal_assume_deinit< {ref_kind} < {ty} > >({ref_kind}< {ty} >&) noexcept {{
794}}
795
796template<>
797inline size_t __zngur_internal_size_of< {ref_kind} < {ty} > >() noexcept {{
798 return {size};
799}}
800}}"#,
801 ty = self.ty,
802 size = if is_unsized { 16 } else { 8 },
803 )?;
804 if self.ty.path.to_string() == "::rust::Str" && ref_kind == "Ref" {
805 writeln!(
806 state,
807 r#"
808inline ::rust::Ref<::rust::Str> operator""_rs(const char* input, size_t len) {{
809 ::rust::Ref<::rust::Str> o;
810 o.data[0] = reinterpret_cast<size_t>(input);
811 o.data[1] = len;
812 return o;
813}}
814 "#,
815 )?;
816 }
817 }
818 Ok(())
819 }
820
821 fn emit(&self, state: &mut State) -> std::fmt::Result {
822 let is_copy = self
823 .wellknown_traits
824 .contains(&ZngurWellknownTraitData::Copy);
825 writeln!(
826 state,
827 r#"
828namespace rust {{
829 template<>
830 inline uint8_t* __zngur_internal_data_ptr< {ty} >(const {ty}& t) noexcept ;
831 template<>
832 inline void __zngur_internal_check_init< {ty} >(const {ty}& t) noexcept ;
833 template<>
834 inline void __zngur_internal_assume_init< {ty} >({ty}& t) noexcept ;
835 template<>
836 inline void __zngur_internal_assume_deinit< {ty} >({ty}& t) noexcept ;
837 template<>
838 inline size_t __zngur_internal_size_of< {ty} >() noexcept ;
839}}"#,
840 ty = self.ty,
841 )?;
842 self.ty.path.emit_in_namespace(state, |state| {
843 if self.ty.path.0 == ["rust", "Unit"] {
844 write!(
845 state,
846 "template<> struct Tuple<> {{ ::std::array< ::uint8_t, 1> data; }};"
847 )?;
848 return Ok(());
849 } else {
850 self.ty.emit_specialization_decl(state)?;
851 }
852 match self.layout {
853 CppLayoutPolicy::OnlyByRef => {
854 writeln!(
855 state,
856 r#"
857{{
858public:
859 {ty}() = delete;
860 "#,
861 ty = self.ty.path.name(),
862 )?;
863 }
864 CppLayoutPolicy::HeapAllocated { .. } | CppLayoutPolicy::StackAllocated { .. } => {
865 match self.layout {
866 CppLayoutPolicy::StackAllocated { size, align } => {
867 writeln!(
868 state,
869 r#"
870{{
871private:
872 alignas({align}) mutable ::std::array<uint8_t, {size}> data;
873 "#,
874 )?;
875 }
876 CppLayoutPolicy::HeapAllocated { .. } => {
877 writeln!(
878 state,
879 r#"
880{{
881private:
882 uint8_t* data;
883 "#,
884 )?;
885 }
886 CppLayoutPolicy::OnlyByRef => unreachable!(),
887 }
888 writeln!(
889 state,
890 r#"
891 friend uint8_t* ::rust::__zngur_internal_data_ptr< {ty} >(const {ty}& t) noexcept ;
892 friend void ::rust::__zngur_internal_check_init< {ty} >(const {ty}& t) noexcept ;
893 friend void ::rust::__zngur_internal_assume_init< {ty} >({ty}& t) noexcept ;
894 friend void ::rust::__zngur_internal_assume_deinit< {ty} >({ty}& t) noexcept ;
895 friend ::rust::ZngurPrettyPrinter< {ty} >;
896"#,
897 ty = self.ty,
898 )?;
899 if self.ty.path.to_string() == "::rust::Bool" {
900 assert_eq!(
901 self.layout,
902 CppLayoutPolicy::StackAllocated { size: 1, align: 1 }
903 );
904 assert!(is_copy);
905 writeln!(
906 state,
907 r#"
908public:
909 operator bool() {{
910 return data[0];
911 }}
912 Bool(bool b) {{
913 data[0] = b;
914 }}
915private:
916 "#,
917 )?;
918 }
919 if !is_copy {
920 writeln!(state, " bool drop_flag;")?;
921 }
922 let (alloc_heap, free_heap, copy_data) = match &self.layout {
923 CppLayoutPolicy::StackAllocated { .. } => (
924 "".to_owned(),
925 "".to_owned(),
926 "this->data = other.data;".to_owned(),
927 ),
928 CppLayoutPolicy::HeapAllocated {
929 size_fn,
930 alloc_fn,
931 free_fn,
932 } => (
933 format!("data = {alloc_fn}();"),
934 format!("{free_fn}(data);"),
935 format!("memcpy(this->data, other.data, {size_fn}());"),
936 ),
937 CppLayoutPolicy::OnlyByRef => unreachable!(),
938 };
939 writeln!(state, "public:")?;
940 if is_copy {
941 writeln!(
942 state,
943 r#"
944 {ty}() {{ {alloc_heap} }}
945 ~{ty}() {{ {free_heap} }}
946 {ty}(const {ty}& other) {{
947 {alloc_heap}
948 {copy_data}
949 }}
950 {ty}& operator=(const {ty}& other) {{
951 {copy_data}
952 return *this;
953 }}
954 {ty}({ty}&& other) {{
955 {alloc_heap}
956 {copy_data}
957 }}
958 {ty}& operator=({ty}&& other) {{
959 {copy_data}
960 return *this;
961 }}
962 "#,
963 ty = self.ty.path.name(),
964 )?;
965 } else {
966 let drop_in_place = self
967 .wellknown_traits
968 .iter()
969 .find_map(|x| match x {
970 ZngurWellknownTraitData::Drop { drop_in_place } => {
971 Some(drop_in_place)
972 }
973 _ => None,
974 })
975 .unwrap();
976 writeln!(
977 state,
978 r#"
979 {ty}() : drop_flag(false) {{ {alloc_heap} }}
980 ~{ty}() {{
981 if (drop_flag) {{
982 {drop_in_place}(&data[0]);
983 }}
984 {free_heap}
985 }}
986 {ty}(const {ty}& other) = delete;
987 {ty}& operator=(const {ty}& other) = delete;
988 {ty}({ty}&& other) : drop_flag(false) {{
989 {alloc_heap}
990 *this = ::std::move(other);
991 }}
992 {ty}& operator=({ty}&& other) {{
993 if (this != &other)
994 {{
995 if (drop_flag) {{
996 {drop_in_place}(&data[0]);
997 }}
998 this->drop_flag = other.drop_flag;
999 {copy_data}
1000 other.drop_flag = false;
1001 }}
1002 return *this;
1003 }}
1004 "#,
1005 ty = self.ty.path.name(),
1006 )?;
1007 }
1008 match &self.from_trait {
1009 Some(RustTrait::Fn { inputs, output, .. }) => {
1010 let as_std_function = format!(
1011 "::std::function< {}({})>",
1012 output.into_cpp(),
1013 inputs.iter().map(|x| x.into_cpp()).join(", ")
1014 );
1015 writeln!(
1016 state,
1017 r#"
1018 static inline {ty} make_box({as_std_function} f);
1019 "#,
1020 ty = self.ty.path.name(),
1021 )?;
1022 }
1023 Some(RustTrait::Normal { .. }) => {
1024 writeln!(
1025 state,
1026 r#"
1027 template<typename T, typename... Args>
1028 static {ty} make_box(Args&&... args);
1029 "#,
1030 ty = self.ty.path.name(),
1031 )?;
1032 }
1033 None => (),
1034 }
1035 }
1036 }
1037 if let Some(CppValue(rust_link_name, cpp_ty)) = &self.cpp_value {
1038 writeln!(
1039 state,
1040 r#"
1041 inline {cpp_ty}& cpp() {{
1042 return (*{rust_link_name}(&data[0])).as_cpp< {cpp_ty} >();
1043 }}"#
1044 )?;
1045 }
1046 for method in &self.methods {
1047 write!(state, "static ")?;
1048 method.sig.emit_cpp_header(state, &method.name)?;
1049 if method.kind != ZngurMethodReceiver::Static {
1050 let CppFnSig {
1051 rust_link_name: _,
1052 inputs,
1053 output,
1054 } = &method.sig;
1055 writeln!(
1056 state,
1057 "{output} {fn_name}({input_defs}) {const_kw} noexcept ;",
1058 fn_name = &method.name,
1059 input_defs = inputs
1060 .iter()
1061 .skip(1)
1062 .enumerate()
1063 .map(|(n, ty)| format!("{ty} i{n}"))
1064 .join(", "),
1065 const_kw = if method.kind != ZngurMethodReceiver::Ref(Mutability::Not) {
1066 ""
1067 } else {
1068 "const"
1069 },
1070 )?;
1071 }
1072 }
1073 for constructor in &self.constructors {
1074 writeln!(
1075 state,
1076 "{fn_name}({input_defs}) noexcept ;",
1077 fn_name = &self.ty.path.0.last().unwrap(),
1078 input_defs = constructor
1079 .inputs
1080 .iter()
1081 .enumerate()
1082 .map(|(n, ty)| format!("{ty} i{n}"))
1083 .join(", "),
1084 )?;
1085 }
1086 for field in &self.fields {
1087 writeln!(
1088 state,
1089 "[[no_unique_address]] ::rust::FieldOwned<{}, {}> {};",
1090 field.ty.into_cpp(),
1091 field.offset,
1092 cpp_handle_field_name(&field.name),
1093 )?;
1094 }
1095 writeln!(state, "}};")
1096 })?;
1097 let ty = &self.ty;
1098 if self.layout != CppLayoutPolicy::OnlyByRef {
1099 match &self.layout {
1100 CppLayoutPolicy::StackAllocated { size, align: _ } => {
1101 writeln!(
1102 state,
1103 r#"
1104namespace rust {{
1105 template<>
1106 inline size_t __zngur_internal_size_of< {ty} >() noexcept {{
1107 return {size};
1108 }}
1109 "#,
1110 )?;
1111 }
1112 CppLayoutPolicy::HeapAllocated { size_fn, .. } => {
1113 writeln!(
1114 state,
1115 r#"
1116namespace rust {{
1117 template<>
1118 inline size_t __zngur_internal_size_of< {ty} >() noexcept {{
1119 return {size_fn}();
1120 }}
1121 "#,
1122 )?;
1123 }
1124 CppLayoutPolicy::OnlyByRef => unreachable!(),
1125 }
1126
1127 if is_copy {
1128 writeln!(
1129 state,
1130 r#"
1131 template<>
1132 inline void __zngur_internal_check_init< {ty} >(const {ty}&) noexcept {{
1133 }}
1134
1135 template<>
1136 inline void __zngur_internal_assume_init< {ty} >({ty}&) noexcept {{
1137 }}
1138
1139 template<>
1140 inline void __zngur_internal_assume_deinit< {ty} >({ty}&) noexcept {{
1141 }}
1142"#,
1143 )?;
1144 } else {
1145 writeln!(
1146 state,
1147 r#"
1148 template<>
1149 inline void __zngur_internal_check_init< {ty} >(const {ty}& t) noexcept {{
1150 if (!t.drop_flag) {{
1151 ::std::cerr << "Use of uninitialized or moved Zngur Rust object with type {ty}" << ::std::endl;
1152 while (true) raise(SIGSEGV);
1153 }}
1154 }}
1155
1156 template<>
1157 inline void __zngur_internal_assume_init< {ty} >({ty}& t) noexcept {{
1158 t.drop_flag = true;
1159 }}
1160
1161 template<>
1162 inline void __zngur_internal_assume_deinit< {ty} >({ty}& t) noexcept {{
1163 ::rust::__zngur_internal_check_init< {ty} >(t);
1164 t.drop_flag = false;
1165 }}
1166"#,
1167 )?;
1168 }
1169 writeln!(
1170 state,
1171 r#"
1172 template<>
1173 inline uint8_t* __zngur_internal_data_ptr< {ty} >({ty} const & t) noexcept {{
1174 return const_cast<uint8_t*>(&t.data[0]);
1175 }}
1176}}
1177"#,
1178 )?;
1179 }
1180 self.emit_ref_specialization(state)?;
1181 self.emit_field_specialization(state)?;
1182 Ok(())
1183 }
1184
1185 fn emit_cpp_fn_defs(
1186 &self,
1187 state: &mut State,
1188 traits: &HashMap<RustTrait, CppTraitDefinition>,
1189 ) -> std::fmt::Result {
1190 let is_unsized = self
1191 .wellknown_traits
1192 .contains(&ZngurWellknownTraitData::Unsized);
1193 let cpp_type = &self.ty.to_string();
1194 let my_name = cpp_type.strip_prefix("::").unwrap();
1195 for c in &self.constructors {
1196 let fn_name = my_name.to_owned() + "::" + self.ty.path.0.last().unwrap();
1197 let CppFnSig {
1198 inputs,
1199 output: _,
1200 rust_link_name,
1201 } = c;
1202 writeln!(
1203 state,
1204 "inline {fn_name}({input_defs}) noexcept {{
1205 ::rust::__zngur_internal_assume_init(*this);
1206 {rust_link_name}({input_args}::rust::__zngur_internal_data_ptr(*this));
1207 {deinits}
1208 }}",
1209 input_defs = inputs
1210 .iter()
1211 .enumerate()
1212 .map(|(n, ty)| format!("{ty} i{n}"))
1213 .join(", "),
1214 input_args = (0..inputs.len())
1215 .map(|n| format!("::rust::__zngur_internal_data_ptr(i{n}), "))
1216 .join(""),
1217 deinits = (0..inputs.len())
1218 .map(|n| format!("::rust::__zngur_internal_assume_deinit(i{n});"))
1219 .join("\n"),
1220 )?;
1221 }
1222 match self.from_trait.as_ref().and_then(|k| traits.get(k)) {
1223 Some(CppTraitDefinition::Fn { sig }) => {
1224 let as_std_function = format!(
1225 "::std::function< {}({})>",
1226 sig.output,
1227 sig.inputs.iter().join(", ")
1228 );
1229 let ii_names = sig
1230 .inputs
1231 .iter()
1232 .enumerate()
1233 .map(|(n, x)| format!("::rust::__zngur_internal_move_from_rust< {x} >(i{n})"))
1234 .join(", ");
1235 let uint8_t_ix = sig
1236 .inputs
1237 .iter()
1238 .enumerate()
1239 .map(|(n, _)| format!("uint8_t* i{n},"))
1240 .join(" ");
1241 let out_ty = &sig.output;
1242 writeln!(
1243 state,
1244 r#"
1245{my_name} {my_name}::make_box({as_std_function} f) {{
1246auto data = new {as_std_function}(f);
1247{my_name} o;
1248::rust::__zngur_internal_assume_init(o);
1249{link_name}(
1250reinterpret_cast<uint8_t*>(data),
1251[](uint8_t *d) {{ delete reinterpret_cast< {as_std_function}*>(d); }},
1252[](uint8_t *d, {uint8_t_ix} uint8_t *o) {{
1253auto dd = reinterpret_cast< {as_std_function} *>(d);
1254{out_ty} oo = (*dd)({ii_names});
1255::rust::__zngur_internal_move_to_rust< {out_ty} >(o, oo);
1256}},
1257::rust::__zngur_internal_data_ptr(o));
1258return o;
1259}}
1260"#,
1261 link_name = sig.rust_link_name,
1262 )?;
1263 }
1264 Some(CppTraitDefinition::Normal {
1265 as_ty,
1266 methods: _,
1267 link_name,
1268 link_name_ref: _,
1269 }) => {
1270 writeln!(
1271 state,
1272 r#"
1273template<typename T, typename... Args>
1274{my_name} {my_name}::make_box(Args&&... args) {{
1275auto data = new T(::std::forward<Args>(args)...);
1276auto data_as_impl = dynamic_cast< {as_ty}*>(data);
1277{my_name} o;
1278::rust::__zngur_internal_assume_init(o);
1279{link_name}(
1280reinterpret_cast<uint8_t*>(data_as_impl),
1281[](uint8_t *d) {{ delete reinterpret_cast< {as_ty} *>(d); }},
1282"#,
1283 )?;
1284 writeln!(
1285 state,
1286 r#"
1287::rust::__zngur_internal_data_ptr(o));
1288return o;
1289}}
1290"#,
1291 )?;
1292 }
1293 None => (),
1294 }
1295 match self.from_trait_ref.as_ref().and_then(|k| traits.get(k)) {
1296 Some(CppTraitDefinition::Fn { .. }) => {
1297 todo!()
1298 }
1299 Some(CppTraitDefinition::Normal {
1300 as_ty,
1301 methods: _,
1302 link_name: _,
1303 link_name_ref,
1304 }) => {
1305 for ref_kind in ["Ref", " RefMut"] {
1306 writeln!(
1307 state,
1308 r#"
1309rust::{ref_kind}< {my_name} >::{ref_kind}({as_ty}& args) {{
1310auto data_as_impl = &args;
1311::rust::__zngur_internal_assume_init(*this);
1312{link_name_ref}(
1313(uint8_t *)data_as_impl,
1314"#,
1315 )?;
1316 writeln!(
1317 state,
1318 r#"
1319::rust::__zngur_internal_data_ptr(*this));
1320}}
1321"#,
1322 )?;
1323 }
1324 }
1325 None => (),
1326 }
1327 for method in &self.methods {
1328 let fn_name = my_name.to_owned() + "::" + &method.name;
1329 method.sig.emit_cpp_def(state, &fn_name)?;
1330 if let ZngurMethodReceiver::Ref(m) = method.kind {
1331 let ref_kinds: &[&str] = match m {
1332 Mutability::Mut => &["RefMut"],
1333 Mutability::Not => &["Ref", "RefMut"],
1334 };
1335 let field_kinds: &[&str] = match m {
1336 Mutability::Mut => &["FieldOwned", "FieldRefMut"],
1337 Mutability::Not => &["FieldOwned", "FieldRefMut", "FieldRef"],
1338 };
1339 for field_kind in field_kinds {
1340 let CppFnSig {
1341 rust_link_name: _,
1342 inputs,
1343 output,
1344 } = &method.sig;
1345 writeln!(
1346 state,
1347 "template<size_t OFFSET>
1348 inline {output} rust::{field_kind}< {ty}, OFFSET >::{method_name}({input_defs}) const noexcept {{
1349 return {fn_name}(*this{input_args});
1350 }}",
1351 ty = &self.ty,
1352 method_name = &method.name,
1353 input_defs = inputs
1354 .iter()
1355 .skip(1)
1356 .enumerate()
1357 .map(|(n, ty)| format!("{ty} i{n}"))
1358 .join(", "),
1359 input_args = (0..inputs.len() - 1)
1360 .map(|n| format!(", ::std::move(i{n})"))
1361 .join("")
1362 )?;
1363 }
1364 for ref_kind in ref_kinds {
1365 let CppFnSig {
1366 rust_link_name: _,
1367 inputs,
1368 output,
1369 } = &method.sig;
1370 writeln!(
1371 state,
1372 "inline {output} rust::{ref_kind}< {ty} >::{method_name}({input_defs}) const noexcept {{
1373 return {fn_name}(*this{input_args});
1374 }}",
1375 ty = &self.ty,
1376 method_name = &method.name,
1377 input_defs = inputs
1378 .iter()
1379 .skip(1)
1380 .enumerate()
1381 .map(|(n, ty)| format!("{ty} i{n}"))
1382 .join(", "),
1383 input_args = (0..inputs.len() - 1)
1384 .map(|n| format!(", ::std::move(i{n})"))
1385 .join("")
1386 )?;
1387 }
1388 }
1389 if !is_unsized
1390 && !matches!(self.layout, CppLayoutPolicy::OnlyByRef)
1391 && method.kind != ZngurMethodReceiver::Static
1392 {
1393 let CppFnSig {
1394 rust_link_name: _,
1395 inputs,
1396 output,
1397 } = &method.sig;
1398 writeln!(
1399 state,
1400 "inline {output} {fn_name}({input_defs}) {const_kw} noexcept {{
1401 return {fn_name}({this_arg}{input_args});
1402 }}",
1403 this_arg = match method.kind {
1404 ZngurMethodReceiver::Ref(_) => "*this",
1405 ZngurMethodReceiver::Move => "::std::move(*this)",
1406 ZngurMethodReceiver::Static => unreachable!(),
1407 },
1408 input_defs = inputs
1409 .iter()
1410 .skip(1)
1411 .enumerate()
1412 .map(|(n, ty)| format!("{ty} i{n}"))
1413 .join(", "),
1414 input_args = (0..inputs.len() - 1)
1415 .map(|n| format!(", ::std::move(i{n})"))
1416 .join(""),
1417 const_kw = if method.kind != ZngurMethodReceiver::Ref(Mutability::Not) {
1418 ""
1419 } else {
1420 "const"
1421 },
1422 )?;
1423 }
1424 }
1425 let is_unsized = self
1426 .wellknown_traits
1427 .contains(&ZngurWellknownTraitData::Unsized);
1428 for tr in &self.wellknown_traits {
1429 match tr {
1430 ZngurWellknownTraitData::Debug {
1431 pretty_print,
1432 debug_print: _, } => {
1434 if !is_unsized {
1435 writeln!(
1436 state,
1437 r#"
1438 namespace rust {{
1439 template<>
1440 struct ZngurPrettyPrinter< {ty} > {{
1441 static inline void print({ty} const& t) {{
1442 ::rust::__zngur_internal_check_init< {ty} >(t);
1443 {pretty_print}(&t.data[0]);
1444 }}
1445 }};
1446
1447 template<>
1448 struct ZngurPrettyPrinter< Ref< {ty} > > {{
1449 static inline void print(Ref< {ty} > const& t) {{
1450 ::rust::__zngur_internal_check_init< Ref< {ty} > >(t);
1451 {pretty_print}(reinterpret_cast<uint8_t*>(t.data));
1452 }}
1453 }};
1454
1455 template<>
1456 struct ZngurPrettyPrinter< RefMut< {ty} > > {{
1457 static inline void print(RefMut< {ty} > const& t) {{
1458 ::rust::__zngur_internal_check_init< RefMut< {ty} > >(t);
1459 {pretty_print}(reinterpret_cast<uint8_t*>(t.data));
1460 }}
1461 }};
1462
1463 template<size_t OFFSET>
1464 struct ZngurPrettyPrinter< FieldOwned< {ty}, OFFSET > > {{
1465 static inline void print(FieldOwned< {ty}, OFFSET > const& t) {{
1466 ZngurPrettyPrinter< Ref< {ty} > >::print(t);
1467 }}
1468 }};
1469
1470 template<size_t OFFSET>
1471 struct ZngurPrettyPrinter< FieldRef< {ty}, OFFSET > > {{
1472 static inline void print(FieldRef< {ty}, OFFSET > const& t) {{
1473 ZngurPrettyPrinter< Ref< {ty} > >::print(t);
1474 }}
1475 }};
1476
1477 template<size_t OFFSET>
1478 struct ZngurPrettyPrinter< FieldRefMut< {ty}, OFFSET > > {{
1479 static inline void print(FieldRefMut< {ty}, OFFSET > const& t) {{
1480 ZngurPrettyPrinter< Ref< {ty} > >::print(t);
1481 }}
1482 }};
1483 }}"#,
1484 ty = self.ty,
1485 )?;
1486 } else {
1487 writeln!(
1488 state,
1489 r#"
1490 namespace rust {{
1491 template<>
1492 struct ZngurPrettyPrinter< Ref< {ty} > > {{
1493 static inline void print(Ref< {ty} > const& t) {{
1494 ::rust::__zngur_internal_check_init< Ref< {ty} > >(t);
1495 {pretty_print}(::rust::__zngur_internal_data_ptr< Ref< {ty} > >(t));
1496 }}
1497 }};
1498
1499 template<>
1500 struct ZngurPrettyPrinter< RefMut< {ty} > > {{
1501 static inline void print(RefMut< {ty} > const& t) {{
1502 ::rust::__zngur_internal_check_init< RefMut< {ty} > >(t);
1503 {pretty_print}(::rust::__zngur_internal_data_ptr< RefMut< {ty} > >(t));
1504 }}
1505 }};
1506 }}"#,
1507 ty = self.ty,
1508 )?;
1509 }
1510 }
1511 ZngurWellknownTraitData::Unsized
1512 | ZngurWellknownTraitData::Copy
1513 | ZngurWellknownTraitData::Drop { .. } => {}
1514 }
1515 }
1516 Ok(())
1517 }
1518
1519 fn emit_rust_links(&self, state: &mut State) -> std::fmt::Result {
1520 for method in &self.methods {
1521 method.sig.emit_rust_link_decl(state)?;
1522 }
1523 for c in &self.constructors {
1524 c.emit_rust_link_decl(state)?;
1525 }
1526 if let Some(cpp_value) = &self.cpp_value {
1527 writeln!(
1528 state,
1529 "::rust::ZngurCppOpaqueOwnedObject* {}(uint8_t*);",
1530 cpp_value.0
1531 )?;
1532 }
1533 if let CppLayoutPolicy::HeapAllocated {
1534 size_fn,
1535 alloc_fn,
1536 free_fn,
1537 } = &self.layout
1538 {
1539 writeln!(state, "size_t {size_fn}();")?;
1540 writeln!(state, "uint8_t* {alloc_fn}();")?;
1541 writeln!(state, "void {free_fn}(uint8_t*);")?;
1542 }
1543 for tr in &self.wellknown_traits {
1544 match tr {
1545 ZngurWellknownTraitData::Debug {
1546 pretty_print,
1547 debug_print,
1548 } => {
1549 writeln!(state, "void {pretty_print}(uint8_t *data);")?;
1550 writeln!(state, "void {debug_print}(uint8_t *data);")?;
1551 }
1552 ZngurWellknownTraitData::Unsized | ZngurWellknownTraitData::Copy => (),
1553 ZngurWellknownTraitData::Drop { drop_in_place } => {
1554 writeln!(state, "void {drop_in_place}(uint8_t *data);")?;
1555 }
1556 }
1557 }
1558 Ok(())
1559 }
1560}
1561
1562#[derive(Default)]
1563pub struct CppFile {
1564 pub type_defs: Vec<CppTypeDefinition>,
1565 pub trait_defs: HashMap<RustTrait, CppTraitDefinition>,
1566 pub fn_defs: Vec<CppFnDefinition>,
1567 pub exported_fn_defs: Vec<CppExportedFnDefinition>,
1568 pub exported_impls: Vec<CppExportedImplDefinition>,
1569 pub additional_includes: String,
1570 pub panic_to_exception: bool,
1571}
1572
1573impl CppFile {
1574 fn emit_h_file(&self, state: &mut State) -> std::fmt::Result {
1575 state.text += r#"
1576#pragma once
1577
1578#include <cstddef>
1579#include <cstdint>
1580#include <cstring>
1581#include <csignal>
1582#include <array>
1583#include <iostream>
1584#include <functional>
1585#include <math.h>
1586"#;
1587 state.text += &self.additional_includes;
1588 if self.panic_to_exception {
1589 state.text += r#"
1590 namespace rust {
1591 class Panic {};
1592 }
1593 extern "C" {
1594 uint8_t __zngur_detect_panic();
1595 void __zngur_take_panic();
1596 }
1597 "#;
1598 }
1599 state.text += r#"
1600#define zngur_dbg(x) (::rust::zngur_dbg_impl(__FILE__, __LINE__, #x, x))
1601
1602namespace rust {
1603 template<typename T>
1604 uint8_t* __zngur_internal_data_ptr(const T& t) noexcept ;
1605
1606 template<typename T>
1607 void __zngur_internal_assume_init(T& t) noexcept ;
1608
1609 template<typename T>
1610 void __zngur_internal_assume_deinit(T& t) noexcept ;
1611
1612 template<typename T>
1613 inline size_t __zngur_internal_size_of() noexcept ;
1614
1615 template<typename T>
1616 inline void __zngur_internal_move_to_rust(uint8_t* dst, T& t) noexcept {
1617 memcpy(dst, ::rust::__zngur_internal_data_ptr(t), ::rust::__zngur_internal_size_of<T>());
1618 ::rust::__zngur_internal_assume_deinit(t);
1619 }
1620
1621 template<typename T>
1622 inline T __zngur_internal_move_from_rust(uint8_t* src) noexcept {
1623 T t;
1624 ::rust::__zngur_internal_assume_init(t);
1625 memcpy(::rust::__zngur_internal_data_ptr(t), src, ::rust::__zngur_internal_size_of<T>());
1626 return t;
1627 }
1628
1629 template<typename T>
1630 inline void __zngur_internal_check_init(const T&) noexcept {
1631 }
1632
1633 class ZngurCppOpaqueOwnedObject {
1634 uint8_t* data;
1635 void (*destructor)(uint8_t*);
1636
1637 public:
1638 template<typename T, typename... Args>
1639 inline static ZngurCppOpaqueOwnedObject build(Args&&... args) {
1640 ZngurCppOpaqueOwnedObject o;
1641 o.data = reinterpret_cast<uint8_t*>(new T(::std::forward<Args>(args)...));
1642 o.destructor = [](uint8_t* d) {
1643 delete reinterpret_cast<T*>(d);
1644 };
1645 return o;
1646 }
1647
1648 template<typename T>
1649 inline T& as_cpp() {
1650 return *reinterpret_cast<T *>(data);
1651 }
1652 };
1653
1654 template<typename T>
1655 struct Ref;
1656
1657 template<typename T>
1658 struct RefMut;
1659
1660 template<typename T, size_t OFFSET>
1661 struct FieldOwned {
1662 inline operator T() const noexcept { return *::rust::Ref<T>(*this); }
1663 };
1664
1665 template<typename T, size_t OFFSET>
1666 struct FieldRef {
1667 inline operator T() const noexcept { return *::rust::Ref<T>(*this); }
1668 };
1669
1670 template<typename T, size_t OFFSET>
1671 struct FieldRefMut {
1672 inline operator T() const noexcept { return *::rust::Ref<T>(*this); }
1673 };
1674
1675 template<typename... T>
1676 struct Tuple;
1677
1678 using Unit = Tuple<>;
1679
1680 template<typename T>
1681 struct ZngurPrettyPrinter;
1682
1683 class Inherent;
1684
1685 template<typename Type, typename Trait = Inherent>
1686 class Impl;
1687
1688 template<typename T>
1689 T&& zngur_dbg_impl(const char* file_name, int line_number, const char* exp, T&& input) {
1690 ::std::cerr << "[" << file_name << ":" << line_number << "] " << exp << " = ";
1691 ZngurPrettyPrinter<typename ::std::remove_reference<T>::type>::print(input);
1692 return ::std::forward<T>(input);
1693 }
1694"#;
1695 for ty in [8, 16, 32, 64]
1696 .into_iter()
1697 .flat_map(|x| [format!("int{x}_t"), format!("uint{x}_t")])
1698 .chain([8, 16, 32, 64].into_iter().flat_map(|x| {
1699 [
1700 format!("::rust::Ref<int{x}_t>"),
1701 format!("::rust::Ref<uint{x}_t>"),
1702 format!("::rust::RefMut<int{x}_t>"),
1703 format!("::rust::RefMut<uint{x}_t>"),
1704 ]
1705 }))
1706 .chain([
1707 "::rust::ZngurCppOpaqueOwnedObject".to_string(),
1708 "::double_t".to_string(),
1709 "::float_t".to_string(),
1710 "::size_t".to_string(),
1711 ])
1712 {
1713 let needs_endif = match ty.as_str() {
1714 "::size_t" => {
1715 writeln!(state, "#if defined(__APPLE__) || defined(__wasm__)")?;
1717 true
1718 }
1719 _ => false,
1720 };
1721 writeln!(
1722 state,
1723 r#"
1724 template<>
1725 inline uint8_t* __zngur_internal_data_ptr< {ty} >(const {ty}& t) noexcept {{
1726 return const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(&t));
1727 }}
1728
1729 template<>
1730 inline void __zngur_internal_assume_init< {ty} >({ty}&) noexcept {{}}
1731 template<>
1732 inline void __zngur_internal_assume_deinit< {ty} >({ty}&) noexcept {{}}
1733
1734 template<>
1735 inline size_t __zngur_internal_size_of< {ty} >() noexcept {{
1736 return sizeof({ty});
1737 }}
1738
1739 template<>
1740 inline uint8_t* __zngur_internal_data_ptr< {ty}*>({ty}* const & t) noexcept {{
1741 return const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(&t));
1742 }}
1743
1744 template<>
1745 inline void __zngur_internal_assume_init< {ty}*>({ty}*&) noexcept {{}}
1746 template<>
1747 inline void __zngur_internal_assume_deinit< {ty}*>({ty}*&) noexcept {{}}
1748
1749 template<>
1750 inline uint8_t* __zngur_internal_data_ptr< {ty} const*>({ty} const* const & t) noexcept {{
1751 return const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(&t));
1752 }}
1753
1754 template<>
1755 inline void __zngur_internal_assume_init< {ty} const*>({ty} const*&) noexcept {{}}
1756 template<>
1757 inline void __zngur_internal_assume_deinit< {ty} const*>({ty} const*&) noexcept {{}}
1758
1759 template<>
1760 struct Ref< {ty} > {{
1761 Ref() {{
1762 data = 0;
1763 }}
1764 Ref(const {ty}& t) {{
1765 data = reinterpret_cast<size_t>(__zngur_internal_data_ptr(t));
1766 }}
1767
1768 template<size_t OFFSET>
1769 Ref(const FieldOwned< {ty}, OFFSET >& f) {{
1770 data = reinterpret_cast<size_t>(&f) + OFFSET;
1771 }}
1772
1773 template<size_t OFFSET>
1774 Ref(const FieldRef< {ty}, OFFSET >& f) {{
1775 data = *reinterpret_cast<const size_t*>(&f) + OFFSET;
1776 }}
1777
1778 template<size_t OFFSET>
1779 Ref(const FieldRefMut< {ty}, OFFSET >& f) {{
1780 data = *reinterpret_cast<const size_t*>(&f) + OFFSET;
1781 }}
1782
1783 {ty}& operator*() {{
1784 return *reinterpret_cast< {ty}*>(data);
1785 }}
1786 private:
1787 size_t data;
1788 friend uint8_t* ::rust::__zngur_internal_data_ptr<Ref< {ty} > >(const ::rust::Ref< {ty} >& t) noexcept ;
1789 friend ::rust::ZngurPrettyPrinter< Ref< {ty} > >;
1790 }};
1791
1792 template<>
1793 struct RefMut< {ty} > {{
1794 RefMut() {{
1795 data = 0;
1796 }}
1797 RefMut({ty}& t) {{
1798 data = reinterpret_cast<size_t>(__zngur_internal_data_ptr(t));
1799 }}
1800
1801 template<size_t OFFSET>
1802 RefMut(const FieldOwned< {ty}, OFFSET >& f) {{
1803 data = reinterpret_cast<size_t>(&f) + OFFSET;
1804 }}
1805
1806 template<size_t OFFSET>
1807 RefMut(const FieldRefMut< {ty}, OFFSET >& f) {{
1808 data = *reinterpret_cast<const size_t*>(&f) + OFFSET;
1809 }}
1810
1811 {ty}& operator*() {{
1812 return *reinterpret_cast< {ty}*>(data);
1813 }}
1814 private:
1815 size_t data;
1816 friend uint8_t* ::rust::__zngur_internal_data_ptr<RefMut< {ty} > >(const ::rust::RefMut< {ty} >& t) noexcept ;
1817 friend ::rust::ZngurPrettyPrinter< Ref< {ty} > >;
1818 }};
1819"#
1820 )?;
1821 if ty.starts_with("int")
1822 || ty.starts_with("uint")
1823 || ty.starts_with("::size_t")
1824 || ty.starts_with("::double")
1825 || ty.starts_with("::float")
1826 {
1827 writeln!(
1828 state,
1829 r#"
1830 template<>
1831 struct ZngurPrettyPrinter<{ty}> {{
1832 static inline void print({ty} const& t) {{
1833 ::std::cerr << t << ::std::endl;
1834 }}
1835 }};
1836 "#
1837 )?;
1838 }
1839
1840 if needs_endif {
1841 writeln!(state, "#endif")?;
1842 }
1843 }
1844 writeln!(state, "}}")?;
1845 writeln!(state, "extern \"C\" {{")?;
1846 for f in &self.fn_defs {
1847 f.sig.emit_rust_link_decl(state)?;
1848 }
1849 for td in &self.type_defs {
1850 td.emit_rust_links(state)?;
1851 }
1852 for (_, td) in &self.trait_defs {
1853 td.emit_rust_links(state)?;
1854 }
1855 writeln!(state, "}}")?;
1856 for td in &self.type_defs {
1857 td.ty.emit_header(state)?;
1858 }
1859 for imp in &self.exported_impls {
1860 imp.ty.emit_header(state)?;
1861 if let Some(tr) = &imp.tr {
1862 tr.emit_header(state)?;
1863 }
1864 }
1865 for (_, td) in &self.trait_defs {
1866 td.emit(state)?;
1867 }
1868 for td in &self.type_defs {
1869 td.emit(state)?;
1870 }
1871 for td in &self.type_defs {
1872 td.emit_cpp_fn_defs(state, &self.trait_defs)?;
1873 }
1874 for fd in &self.fn_defs {
1875 fd.emit_cpp_def(state)?;
1876 }
1877 for func in &self.exported_fn_defs {
1878 writeln!(state, "namespace rust {{ namespace exported_functions {{")?;
1879 write!(state, " {} {}(", func.sig.output, func.name)?;
1880 for (n, ty) in func.sig.inputs.iter().enumerate() {
1881 if n != 0 {
1882 write!(state, ", ")?;
1883 }
1884 write!(state, "{ty} i{n}")?;
1885 }
1886 writeln!(state, ");")?;
1887 writeln!(state, "}} }}")?;
1888 }
1889 for imp in &self.exported_impls {
1890 writeln!(
1891 state,
1892 "namespace rust {{ template<> class Impl< {}, {} > {{ public:",
1893 imp.ty,
1894 match &imp.tr {
1895 Some(x) => format!("{x}"),
1896 None => "::rust::Inherent".to_string(),
1897 }
1898 )?;
1899 for (name, sig) in &imp.methods {
1900 write!(state, " static {} {}(", sig.output, name)?;
1901 for (n, ty) in sig.inputs.iter().enumerate() {
1902 if n != 0 {
1903 write!(state, ", ")?;
1904 }
1905 write!(state, "{ty} i{n}")?;
1906 }
1907 writeln!(state, ");")?;
1908 }
1909 writeln!(state, "}}; }}")?;
1910 }
1911 Ok(())
1912 }
1913
1914 fn emit_cpp_file(&self, state: &mut State, is_really_needed: &mut bool) -> std::fmt::Result {
1915 writeln!(state, r#"#include "./generated.h""#)?;
1916 writeln!(state, "extern \"C\" {{")?;
1917 for t in &self.trait_defs {
1918 *is_really_needed = true;
1919 t.1.emit_cpp(state)?;
1920 }
1921 for func in &self.exported_fn_defs {
1922 *is_really_needed = true;
1923 func.sig.emit_rust_link(state)?;
1924 writeln!(state, "{{")?;
1925 writeln!(
1926 state,
1927 " {} oo = ::rust::exported_functions::{}({});",
1928 func.sig.output,
1929 func.name,
1930 func.sig
1931 .inputs
1932 .iter()
1933 .enumerate()
1934 .map(|(n, ty)| {
1935 format!("::rust::__zngur_internal_move_from_rust< {ty} >(i{n})")
1936 })
1937 .join(", "),
1938 )?;
1939 writeln!(state, " ::rust::__zngur_internal_move_to_rust(o, oo);")?;
1940 writeln!(state, "}}")?;
1941 }
1942 for imp in &self.exported_impls {
1943 *is_really_needed = true;
1944 for (name, sig) in &imp.methods {
1945 sig.emit_rust_link(state)?;
1946 writeln!(state, "{{")?;
1947 writeln!(
1948 state,
1949 " {} oo = ::rust::Impl< {}, {} >::{}({});",
1950 sig.output,
1951 imp.ty,
1952 match &imp.tr {
1953 Some(x) => format!("{x}"),
1954 None => "::rust::Inherent".to_string(),
1955 },
1956 name,
1957 sig.inputs
1958 .iter()
1959 .enumerate()
1960 .map(|(n, ty)| {
1961 format!("::rust::__zngur_internal_move_from_rust< {ty} >(i{n})")
1962 })
1963 .join(", "),
1964 )?;
1965 writeln!(state, " ::rust::__zngur_internal_move_to_rust(o, oo);")?;
1966 writeln!(state, "}}")?;
1967 }
1968 }
1969 writeln!(state, "}}")?;
1970 Ok(())
1971 }
1972
1973 pub fn render(self) -> (String, Option<String>) {
1974 let mut h_file = State {
1975 text: "".to_owned(),
1976 panic_to_exception: self.panic_to_exception,
1977 };
1978 let mut cpp_file = State {
1979 text: "".to_owned(),
1980 panic_to_exception: self.panic_to_exception,
1981 };
1982 self.emit_h_file(&mut h_file).unwrap();
1983 let mut is_cpp_needed = false;
1984 self.emit_cpp_file(&mut cpp_file, &mut is_cpp_needed)
1985 .unwrap();
1986 h_file.remove_no_except_in_panic();
1987 (h_file.text, is_cpp_needed.then_some(cpp_file.text))
1988 }
1989}
1990
1991pub fn cpp_handle_keyword(name: &str) -> &str {
1992 match name {
1993 "new" => "new_",
1994 "default" => "default_",
1995 x => x,
1996 }
1997}
1998
1999pub fn cpp_handle_field_name(name: &str) -> String {
2000 if name.parse::<u32>().is_ok() {
2001 return format!("f{name}");
2002 }
2003 cpp_handle_keyword(name).to_owned()
2004}