1use std::fmt::Write;
2
3use itertools::Itertools;
4
5use crate::{
6 ZngurTrait, ZngurWellknownTrait, ZngurWellknownTraitData,
7 cpp::{CppLayoutPolicy, CppPath, CppTraitDefinition, CppTraitMethod, CppType},
8};
9
10use zngur_def::*;
11
12pub trait IntoCpp {
13 fn into_cpp(&self) -> CppType;
14}
15
16impl IntoCpp for RustPathAndGenerics {
17 fn into_cpp(&self) -> CppType {
18 let RustPathAndGenerics {
19 path,
20 generics,
21 named_generics,
22 } = self;
23 let named_generics = named_generics.iter().sorted_by_key(|x| &x.0).map(|x| &x.1);
24 CppType {
25 path: CppPath::from_rust_path(path),
26 generic_args: generics
27 .iter()
28 .chain(named_generics)
29 .map(|x| x.into_cpp())
30 .collect(),
31 }
32 }
33}
34
35impl IntoCpp for RustTrait {
36 fn into_cpp(&self) -> CppType {
37 match self {
38 RustTrait::Normal(pg) => pg.into_cpp(),
39 RustTrait::Fn {
40 name,
41 inputs,
42 output,
43 } => CppType {
44 path: CppPath::from(&*format!("rust::{name}")),
45 generic_args: inputs
46 .iter()
47 .chain(Some(&**output))
48 .map(|x| x.into_cpp())
49 .collect(),
50 },
51 }
52 }
53}
54
55impl IntoCpp for RustType {
56 fn into_cpp(&self) -> CppType {
57 fn for_builtin(this: &RustType) -> Option<CppType> {
58 match this {
59 RustType::Primitive(s) => match s {
60 PrimitiveRustType::Uint(s) => Some(CppType::from(&*format!("uint{s}_t"))),
61 PrimitiveRustType::Int(s) => Some(CppType::from(&*format!("int{s}_t"))),
62 PrimitiveRustType::Float(32) => Some(CppType::from("float_t")),
63 PrimitiveRustType::Float(64) => Some(CppType::from("double_t")),
64 PrimitiveRustType::Float(_) => unreachable!(),
65 PrimitiveRustType::Usize => Some(CppType::from("size_t")),
66 PrimitiveRustType::Bool | PrimitiveRustType::Str => None,
67 PrimitiveRustType::ZngurCppOpaqueOwnedObject => {
68 Some(CppType::from("rust::ZngurCppOpaqueOwnedObject"))
69 }
70 },
71 RustType::Raw(Mutability::Mut, t) => Some(CppType::from(&*format!(
72 "{}*",
73 for_builtin(t)?.to_string().strip_prefix("::")?
74 ))),
75 RustType::Raw(Mutability::Not, t) => Some(CppType::from(&*format!(
76 "{} const*",
77 for_builtin(t)?.to_string().strip_prefix("::")?
78 ))),
79 _ => None,
80 }
81 }
82 if let Some(builtin) = for_builtin(self) {
83 return builtin;
84 }
85 match self {
86 RustType::Primitive(s) => match s {
87 PrimitiveRustType::Bool => CppType::from("rust::Bool"),
88 PrimitiveRustType::Str => CppType::from("rust::Str"),
89 _ => unreachable!(),
90 },
91 RustType::Boxed(t) => CppType {
92 path: CppPath::from("rust::Box"),
93 generic_args: vec![t.into_cpp()],
94 },
95 RustType::Ref(m, t) => CppType {
96 path: match m {
97 Mutability::Mut => CppPath::from("rust::RefMut"),
98 Mutability::Not => CppPath::from("rust::Ref"),
99 },
100 generic_args: vec![t.into_cpp()],
101 },
102 RustType::Slice(s) => CppType {
103 path: CppPath::from("rust::Slice"),
104 generic_args: vec![s.into_cpp()],
105 },
106 RustType::Raw(_, _) => todo!(),
107 RustType::Adt(pg) => pg.into_cpp(),
108 RustType::Tuple(v) => {
109 if v.is_empty() {
110 return CppType::from("rust::Unit");
111 }
112 CppType {
113 path: CppPath::from("rust::Tuple"),
114 generic_args: v.into_iter().map(|x| x.into_cpp()).collect(),
115 }
116 }
117 RustType::Dyn(tr, marker_bounds) => {
118 let tr_as_cpp_type = tr.into_cpp();
119 CppType {
120 path: CppPath::from("rust::Dyn"),
121 generic_args: [tr_as_cpp_type]
122 .into_iter()
123 .chain(
124 marker_bounds
125 .iter()
126 .map(|x| CppType::from(&*format!("rust::{x}"))),
127 )
128 .collect(),
129 }
130 }
131 }
132 }
133}
134
135pub struct RustFile {
136 pub text: String,
137 pub panic_to_exception: bool,
138}
139
140impl Default for RustFile {
141 fn default() -> Self {
142 Self {
143 text: r#"
144#[allow(dead_code)]
145mod zngur_types {
146 pub struct ZngurCppOpaqueBorrowedObject(());
147
148 #[repr(C)]
149 pub struct ZngurCppOpaqueOwnedObject {
150 data: *mut u8,
151 destructor: extern "C" fn(*mut u8),
152 }
153
154 impl ZngurCppOpaqueOwnedObject {
155 pub unsafe fn new(
156 data: *mut u8,
157 destructor: extern "C" fn(*mut u8),
158 ) -> Self {
159 Self { data, destructor }
160 }
161
162 pub fn ptr(&self) -> *mut u8 {
163 self.data
164 }
165 }
166
167 impl Drop for ZngurCppOpaqueOwnedObject {
168 fn drop(&mut self) {
169 (self.destructor)(self.data)
170 }
171 }
172}
173
174#[allow(unused_imports)]
175pub use zngur_types::ZngurCppOpaqueOwnedObject;
176#[allow(unused_imports)]
177pub use zngur_types::ZngurCppOpaqueBorrowedObject;
178"#
179 .to_owned(),
180 panic_to_exception: false,
181 }
182 }
183}
184
185impl Write for RustFile {
186 fn write_str(&mut self, s: &str) -> std::fmt::Result {
187 self.text.write_str(s)
188 }
189}
190
191macro_rules! w {
192 ($dst:expr, $($arg:tt)*) => {
193 { let _ = write!($dst, $($arg)*); }
194 };
195}
196
197macro_rules! wln {
198 ($dst:expr, $($arg:tt)*) => {
199 { let _ = writeln!($dst, $($arg)*); }
200 };
201}
202
203fn mangle_name(name: &str) -> String {
204 let mut name = "__zngur_"
205 .chars()
206 .chain(name.chars().filter(|c| !c.is_whitespace()))
207 .chain(Some('_'))
208 .collect::<String>();
209 let bads = [
210 (1, "::<", 'm'),
211 (1, ">::", 'n'),
212 (1, "->", 'a'),
213 (2, "&", 'r'),
214 (2, "=", 'e'),
215 (2, "<", 'x'),
216 (2, ">", 'y'),
217 (2, "[", 'j'),
218 (2, "]", 'k'),
219 (2, "::", 's'),
220 (2, ",", 'c'),
221 (2, "+", 'l'),
222 (2, "(", 'p'),
223 (2, ")", 'q'),
224 ];
225 while let Some((pos, which)) = bads.iter().filter_map(|x| Some((name.find(x.1)?, x))).min() {
226 name.replace_range(pos..pos + which.1.len(), "_");
227 w!(name, "{}{pos}", which.2);
228 }
229 name
230}
231
232pub struct ConstructorMangledNames {
233 pub constructor: String,
234 pub match_check: String,
235}
236
237impl RustFile {
238 fn call_cpp_function(&mut self, name: &str, inputs: usize) {
239 for n in 0..inputs {
240 wln!(self, "let mut i{n} = ::core::mem::MaybeUninit::new(i{n});")
241 }
242 wln!(self, "let mut r = ::core::mem::MaybeUninit::uninit();");
243 w!(self, "{name}");
244 for n in 0..inputs {
245 w!(self, "i{n}.as_mut_ptr() as *mut u8, ");
246 }
247 wln!(self, "r.as_mut_ptr() as *mut u8);");
248 wln!(self, "r.assume_init()");
249 }
250
251 pub fn add_static_is_copy_assert(&mut self, ty: &RustType) {
252 wln!(
253 self,
254 r#"const _: () = {{
255 const fn static_assert_is_copy<T: Copy>() {{}}
256 static_assert_is_copy::<{ty}>();
257 }};"#
258 );
259 }
260
261 pub fn add_static_size_assert(&mut self, ty: &RustType, size: usize) {
262 wln!(
263 self,
264 r#"const _: [(); {size}] = [(); ::std::mem::size_of::<{ty}>()];"#
265 );
266 }
267
268 pub fn add_static_align_assert(&mut self, ty: &RustType, align: usize) {
269 wln!(
270 self,
271 r#"const _: [(); {align}] = [(); ::std::mem::align_of::<{ty}>()];"#
272 );
273 }
274
275 pub(crate) fn add_builder_for_dyn_trait(&mut self, tr: &ZngurTrait) -> CppTraitDefinition {
276 assert!(matches!(tr.tr, RustTrait::Normal { .. }));
277 let mut method_mangled_name = vec![];
278 wln!(self, r#"unsafe extern "C" {{"#);
279 for method in &tr.methods {
280 let name = mangle_name(&tr.tr.to_string()) + "_" + &method.name;
281 wln!(
282 self,
283 r#"fn {name}(data: *mut u8, {} o: *mut u8);"#,
284 method
285 .inputs
286 .iter()
287 .enumerate()
288 .map(|(n, _)| format!("i{n}: *mut u8,"))
289 .join(" ")
290 );
291 method_mangled_name.push(name);
292 }
293 wln!(self, "}}");
294 let link_name = self.add_builder_for_dyn_trait_owned(tr, &method_mangled_name);
295 let link_name_ref = self.add_builder_for_dyn_trait_borrowed(tr, &method_mangled_name);
296 CppTraitDefinition::Normal {
297 as_ty: tr.tr.into_cpp(),
298 methods: tr
299 .methods
300 .clone()
301 .into_iter()
302 .zip(method_mangled_name)
303 .map(|(x, rust_link_name)| CppTraitMethod {
304 name: x.name,
305 rust_link_name,
306 inputs: x.inputs.into_iter().map(|x| x.into_cpp()).collect(),
307 output: x.output.into_cpp(),
308 })
309 .collect(),
310 link_name,
311 link_name_ref,
312 }
313 }
314
315 fn add_builder_for_dyn_trait_owned(
316 &mut self,
317 tr: &ZngurTrait,
318 method_mangled_name: &[String],
319 ) -> String {
320 let trait_name = tr.tr.to_string();
321 let (trait_without_assocs, assocs) = tr.tr.clone().take_assocs();
322 let mangled_name = mangle_name(&trait_name);
323 wln!(
324 self,
325 r#"
326#[allow(non_snake_case)]
327#[unsafe(no_mangle)]
328pub extern "C" fn {mangled_name}(
329 data: *mut u8,
330 destructor: extern "C" fn(*mut u8),
331 o: *mut u8,
332) {{
333 struct Wrapper {{
334 value: ZngurCppOpaqueOwnedObject,
335 }}
336 impl {trait_without_assocs} for Wrapper {{
337"#
338 );
339 for (name, ty) in assocs {
340 wln!(self, " type {name} = {ty};");
341 }
342 for (method, rust_link_name) in tr.methods.iter().zip(method_mangled_name) {
343 w!(self, " fn {}(", method.name);
344 match method.receiver {
345 crate::ZngurMethodReceiver::Static => {
346 panic!("traits with static methods are not object safe");
347 }
348 crate::ZngurMethodReceiver::Ref(Mutability::Not) => w!(self, "&self"),
349 crate::ZngurMethodReceiver::Ref(Mutability::Mut) => w!(self, "&mut self"),
350 crate::ZngurMethodReceiver::Move => w!(self, "self"),
351 }
352 for (i, ty) in method.inputs.iter().enumerate() {
353 w!(self, ", i{i}: {ty}");
354 }
355 wln!(self, ") -> {} {{ unsafe {{", method.output);
356 wln!(self, " let data = self.value.ptr();");
357 self.call_cpp_function(&format!("{rust_link_name}(data, "), method.inputs.len());
358 wln!(self, " }} }}");
359 }
360 wln!(
361 self,
362 r#"
363 }}
364 unsafe {{
365 let this = Wrapper {{
366 value: ZngurCppOpaqueOwnedObject::new(data, destructor),
367 }};
368 let r: Box<dyn {trait_name}> = Box::new(this);
369 std::ptr::write(o as *mut _, r)
370 }}
371}}"#
372 );
373 mangled_name
374 }
375
376 fn add_builder_for_dyn_trait_borrowed(
377 &mut self,
378 tr: &ZngurTrait,
379 method_mangled_name: &[String],
380 ) -> String {
381 let trait_name = tr.tr.to_string();
382 let (trait_without_assocs, assocs) = tr.tr.clone().take_assocs();
383 let mangled_name = mangle_name(&trait_name) + "_borrowed";
384 wln!(
385 self,
386 r#"
387#[allow(non_snake_case)]
388#[unsafe(no_mangle)]
389pub extern "C" fn {mangled_name}(
390 data: *mut u8,
391 o: *mut u8,
392) {{
393 struct Wrapper(ZngurCppOpaqueBorrowedObject);
394 impl {trait_without_assocs} for Wrapper {{
395"#
396 );
397 for (name, ty) in assocs {
398 wln!(self, " type {name} = {ty};");
399 }
400 for (method, rust_link_name) in tr.methods.iter().zip(method_mangled_name) {
401 w!(self, " fn {}(", method.name);
402 match method.receiver {
403 crate::ZngurMethodReceiver::Static => {
404 panic!("traits with static methods are not object safe");
405 }
406 crate::ZngurMethodReceiver::Ref(Mutability::Not) => w!(self, "&self"),
407 crate::ZngurMethodReceiver::Ref(Mutability::Mut) => w!(self, "&mut self"),
408 crate::ZngurMethodReceiver::Move => w!(self, "self"),
409 }
410 for (i, ty) in method.inputs.iter().enumerate() {
411 w!(self, ", i{i}: {ty}");
412 }
413 wln!(self, ") -> {} {{ unsafe {{", method.output);
414 wln!(
415 self,
416 " let data = ::std::mem::transmute::<_, *mut u8>(self);"
417 );
418 self.call_cpp_function(&format!("{rust_link_name}(data, "), method.inputs.len());
419 wln!(self, " }} }}");
420 }
421 wln!(
422 self,
423 r#"
424 }}
425 unsafe {{
426 let this = data as *mut Wrapper;
427 let r: &dyn {trait_name} = &*this;
428 std::ptr::write(o as *mut _, r)
429 }}
430}}"#
431 );
432 mangled_name
433 }
434
435 pub fn add_builder_for_dyn_fn(
436 &mut self,
437 name: &str,
438 inputs: &[RustType],
439 output: &RustType,
440 ) -> String {
441 let mangled_name = mangle_name(&inputs.iter().chain(Some(output)).join(", "));
442 let trait_str = format!("{name}({}) -> {output}", inputs.iter().join(", "));
443 wln!(
444 self,
445 r#"
446#[allow(non_snake_case)]
447#[unsafe(no_mangle)]
448pub extern "C" fn {mangled_name}(
449 data: *mut u8,
450 destructor: extern "C" fn(*mut u8),
451 call: extern "C" fn(data: *mut u8, {} o: *mut u8),
452 o: *mut u8,
453) {{
454 let this = unsafe {{ ZngurCppOpaqueOwnedObject::new(data, destructor) }};
455 let r: Box<dyn {trait_str}> = Box::new(move |{}| unsafe {{
456 _ = &this;
457 let data = this.ptr();
458"#,
459 inputs
460 .iter()
461 .enumerate()
462 .map(|(n, _)| format!("i{n}: *mut u8, "))
463 .join(" "),
464 inputs
465 .iter()
466 .enumerate()
467 .map(|(n, ty)| format!("i{n}: {ty}"))
468 .join(", "),
469 );
470 self.call_cpp_function("call(data, ", inputs.len());
471 wln!(
472 self,
473 r#"
474 }});
475 unsafe {{ std::ptr::write(o as *mut _, r) }}
476}}"#
477 );
478 mangled_name
479 }
480
481 pub fn add_tuple_constructor(&mut self, fields: &[RustType]) -> String {
482 let constructor = mangle_name(&fields.iter().join("&"));
483 w!(
484 self,
485 r#"
486#[allow(non_snake_case)]
487#[unsafe(no_mangle)]
488pub extern "C" fn {constructor}("#
489 );
490 for name in 0..fields.len() {
491 w!(self, "f_{name}: *mut u8, ");
492 }
493 w!(
494 self,
495 r#"o: *mut u8) {{ unsafe {{
496 ::std::ptr::write(o as *mut _, ("#
497 );
498 for (name, ty) in fields.iter().enumerate() {
499 w!(self, "::std::ptr::read(f_{name} as *mut {ty}), ");
500 }
501 wln!(self, ")) }} }}");
502 constructor
503 }
504
505 pub fn add_constructor(
506 &mut self,
507 rust_name: &str,
508 args: &[(String, RustType)],
509 ) -> ConstructorMangledNames {
510 let constructor = mangle_name(rust_name);
511 let match_check = format!("{constructor}_check");
512 w!(
513 self,
514 r#"
515#[allow(non_snake_case)]
516#[unsafe(no_mangle)]
517pub extern "C" fn {constructor}("#
518 );
519 for (name, _) in args {
520 w!(self, "f_{name}: *mut u8, ");
521 }
522 w!(
523 self,
524 r#"o: *mut u8) {{ unsafe {{
525 ::std::ptr::write(o as *mut _, {rust_name} {{ "#
526 );
527 for (name, ty) in args {
528 w!(self, "{name}: ::std::ptr::read(f_{name} as *mut {ty}), ");
529 }
530 wln!(self, "}}) }} }}");
531 w!(
532 self,
533 r#"
534#[allow(non_snake_case)]
535#[unsafe(no_mangle)]
536pub extern "C" fn {match_check}(i: *mut u8, o: *mut u8) {{ unsafe {{
537 *o = matches!(&*(i as *mut &_), {rust_name} {{ .. }}) as u8;
538}} }}"#
539 );
540 ConstructorMangledNames {
541 constructor,
542 match_check,
543 }
544 }
545
546 pub(crate) fn add_field_assertions(&mut self, field: &ZngurField, owner: &RustType) {
547 let ZngurField { name, ty, offset } = field;
548 wln!(
549 self,
550 r#"
551 const _: [(); {offset}] = [(); ::std::mem::offset_of!({owner}, {name})];
552 const _: () = {{
553 #[allow(dead_code)]
554 fn check_field(value: {owner}) -> {ty} {{
555 value.{name}
556 }}
557 }};
558 "#
559 );
560 }
561
562 pub fn add_extern_cpp_impl(
563 &mut self,
564 owner: &RustType,
565 tr: Option<&RustTrait>,
566 methods: &[ZngurMethod],
567 ) -> Vec<String> {
568 let mut mangled_names = vec![];
569 w!(self, r#"unsafe extern "C" {{"#);
570 for method in methods {
571 let mn = mangle_name(&format!("{}_extern_method_{}", owner, method.name));
572 w!(
573 self,
574 r#"
575 fn {mn}("#
576 );
577 let input_offset = if method.receiver == ZngurMethodReceiver::Static {
578 0
579 } else {
580 1
581 };
582 for n in 0..method.inputs.len() + input_offset {
583 w!(self, "i{n}: *mut u8, ");
584 }
585 wln!(self, r#"o: *mut u8);"#);
586 mangled_names.push(mn);
587 }
588 w!(self, r#"}}"#);
589 match tr {
590 Some(tr) => {
591 let (tr, assocs) = tr.clone().take_assocs();
592 w!(self, r#"impl {tr} for {owner} {{"#);
593 for (name, ty) in assocs {
594 w!(self, r#"type {name} = {ty};"#);
595 }
596 }
597 None => w!(self, r#"impl {owner} {{"#),
598 }
599 for (mn, method) in mangled_names.iter().zip(methods) {
600 if tr.is_none() {
601 w!(self, "pub ");
602 }
603 w!(self, r#"fn {}("#, method.name);
604 match method.receiver {
605 ZngurMethodReceiver::Static => (),
606 ZngurMethodReceiver::Ref(Mutability::Mut) => w!(self, "&mut self, "),
607 ZngurMethodReceiver::Ref(Mutability::Not) => w!(self, "&self, "),
608 ZngurMethodReceiver::Move => w!(self, "self, "),
609 }
610 let input_offset = if method.receiver == ZngurMethodReceiver::Static {
611 0
612 } else {
613 1
614 };
615 for (ty, n) in method.inputs.iter().zip(input_offset..) {
616 w!(self, "i{n}: {ty}, ");
617 }
618 wln!(self, ") -> {} {{ unsafe {{", method.output);
619 if method.receiver != ZngurMethodReceiver::Static {
620 wln!(self, "let i0 = self;");
621 }
622 self.call_cpp_function(&format!("{mn}("), method.inputs.len() + input_offset);
623 wln!(self, "}} }}");
624 }
625 w!(self, r#"}}"#);
626 mangled_names
627 }
628
629 pub fn add_extern_cpp_function(
630 &mut self,
631 rust_name: &str,
632 inputs: &[RustType],
633 output: &RustType,
634 ) -> String {
635 let mangled_name = mangle_name(rust_name);
636 w!(
637 self,
638 r#"
639unsafe extern "C" {{ fn {mangled_name}("#
640 );
641 for (n, _) in inputs.iter().enumerate() {
642 w!(self, "i{n}: *mut u8, ");
643 }
644 wln!(self, r#"o: *mut u8); }}"#);
645 w!(
646 self,
647 r#"
648pub(crate) fn {rust_name}("#
649 );
650 for (n, ty) in inputs.iter().enumerate() {
651 w!(self, "i{n}: {ty}, ");
652 }
653 wln!(self, ") -> {output} {{ unsafe {{");
654 self.call_cpp_function(&format!("{mangled_name}("), inputs.len());
655 wln!(self, "}} }}");
656 mangled_name
657 }
658
659 pub fn add_cpp_value_bridge(&mut self, ty: &RustType, field: &str) -> String {
660 let mangled_name = mangle_name(&format!("{ty}_cpp_value_{field}"));
661 w!(
662 self,
663 r#"
664#[allow(non_snake_case)]
665#[unsafe(no_mangle)]
666pub extern "C" fn {mangled_name}(d: *mut u8) -> *mut ZngurCppOpaqueOwnedObject {{
667 unsafe {{ &mut (*(d as *mut {ty})).{field} }}
668}}"#
669 );
670 mangled_name
671 }
672
673 pub fn add_function(
674 &mut self,
675 rust_name: &str,
676 inputs: &[RustType],
677 output: &RustType,
678 use_path: Option<Vec<String>>,
679 deref: bool,
680 ) -> String {
681 let mut mangled_name = mangle_name(rust_name);
682 if deref {
683 mangled_name += "_deref_";
684 mangled_name += &mangle_name(&inputs[0].to_string());
685 }
686 w!(
687 self,
688 r#"
689#[allow(non_snake_case)]
690#[unsafe(no_mangle)]
691pub extern "C" fn {mangled_name}("#
692 );
693 for n in 0..inputs.len() {
694 w!(self, "i{n}: *mut u8, ");
695 }
696 wln!(self, "o: *mut u8) {{ unsafe {{");
697 self.wrap_in_catch_unwind(|this| {
698 if let Some(use_path) = use_path {
699 if use_path.first().is_some_and(|x| x == "crate") {
700 wln!(this, " use {};", use_path.iter().join("::"));
701 } else {
702 wln!(this, " use ::{};", use_path.iter().join("::"));
703 }
704 }
705 w!(
706 this,
707 " ::std::ptr::write(o as *mut {output}, {rust_name}("
708 );
709 if deref {
710 w!(this, "&");
711 }
712 for (n, ty) in inputs.iter().enumerate() {
713 w!(this, "::std::ptr::read(i{n} as *mut {ty}), ");
714 }
715 wln!(this, "));");
716 });
717 wln!(self, " }} }}");
718 mangled_name
719 }
720
721 pub(crate) fn add_wellknown_trait(
722 &mut self,
723 ty: &RustType,
724 wellknown_trait: ZngurWellknownTrait,
725 is_unsized: bool,
726 ) -> ZngurWellknownTraitData {
727 match wellknown_trait {
728 ZngurWellknownTrait::Unsized => ZngurWellknownTraitData::Unsized,
729 ZngurWellknownTrait::Copy => ZngurWellknownTraitData::Copy,
730 ZngurWellknownTrait::Drop => {
731 let drop_in_place = mangle_name(&format!("{ty}=drop_in_place"));
732 wln!(
733 self,
734 r#"
735#[allow(non_snake_case)]
736#[unsafe(no_mangle)]
737pub extern "C" fn {drop_in_place}(v: *mut u8) {{ unsafe {{
738 ::std::ptr::drop_in_place(v as *mut {ty});
739}} }}"#
740 );
741 ZngurWellknownTraitData::Drop { drop_in_place }
742 }
743 ZngurWellknownTrait::Debug => {
744 let pretty_print = mangle_name(&format!("{ty}=debug_pretty"));
745 let debug_print = mangle_name(&format!("{ty}=debug_print"));
746 let dbg_ty = if !is_unsized {
747 format!("{ty}")
748 } else {
749 format!("&{ty}")
750 };
751 wln!(
752 self,
753 r#"
754#[allow(non_snake_case)]
755#[unsafe(no_mangle)]
756pub extern "C" fn {pretty_print}(v: *mut u8) {{
757 eprintln!("{{:#?}}", unsafe {{ &*(v as *mut {dbg_ty}) }});
758}}"#
759 );
760 wln!(
761 self,
762 r#"
763#[allow(non_snake_case)]
764#[unsafe(no_mangle)]
765pub extern "C" fn {debug_print}(v: *mut u8) {{
766 eprintln!("{{:?}}", unsafe {{ &*(v as *mut {dbg_ty}) }});
767}}"#
768 );
769 ZngurWellknownTraitData::Debug {
770 pretty_print,
771 debug_print,
772 }
773 }
774 }
775 }
776
777 pub(crate) fn enable_panic_to_exception(&mut self) {
778 wln!(
779 self,
780 r#"thread_local! {{
781 pub static PANIC_PAYLOAD: ::std::cell::Cell<Option<()>> = ::std::cell::Cell::new(None);
782 }}
783 #[allow(non_snake_case)]
784 #[unsafe(no_mangle)]
785 pub fn __zngur_detect_panic() -> u8 {{
786 PANIC_PAYLOAD.with(|p| {{
787 let pp = p.take();
788 let r = if pp.is_some() {{ 1 }} else {{ 0 }};
789 p.set(pp);
790 r
791 }})
792 }}
793
794 #[allow(non_snake_case)]
795 #[unsafe(no_mangle)]
796 pub fn __zngur_take_panic() {{
797 PANIC_PAYLOAD.with(|p| {{
798 p.take();
799 }})
800 }}
801 "#
802 );
803 self.panic_to_exception = true;
804 }
805
806 fn wrap_in_catch_unwind(&mut self, f: impl FnOnce(&mut RustFile)) {
807 if !self.panic_to_exception {
808 f(self);
809 } else {
810 wln!(self, "let e = ::std::panic::catch_unwind(|| {{");
811 f(self);
812 wln!(self, "}});");
813 wln!(
814 self,
815 "if let Err(_) = e {{ PANIC_PAYLOAD.with(|p| p.set(Some(()))) }}"
816 );
817 }
818 }
819
820 pub(crate) fn add_layout_policy_shim(
821 &mut self,
822 ty: &RustType,
823 layout: LayoutPolicy,
824 ) -> CppLayoutPolicy {
825 match layout {
826 LayoutPolicy::StackAllocated { size, align } => {
827 CppLayoutPolicy::StackAllocated { size, align }
828 }
829 LayoutPolicy::HeapAllocated => {
830 let size_fn = mangle_name(&format!("{ty}_size_fn"));
831 let alloc_fn = mangle_name(&format!("{ty}_alloc_fn"));
832 let free_fn = mangle_name(&format!("{ty}_free_fn"));
833 wln!(
834 self,
835 r#"
836 #[allow(non_snake_case)]
837 #[unsafe(no_mangle)]
838 pub fn {size_fn}() -> usize {{
839 ::std::mem::size_of::<{ty}>()
840 }}
841
842 #[allow(non_snake_case)]
843 #[unsafe(no_mangle)]
844 pub fn {alloc_fn}() -> *mut u8 {{
845 unsafe {{ ::std::alloc::alloc(::std::alloc::Layout::new::<{ty}>()) }}
846 }}
847
848 #[allow(non_snake_case)]
849 #[unsafe(no_mangle)]
850 pub fn {free_fn}(p: *mut u8) {{
851 unsafe {{ ::std::alloc::dealloc(p, ::std::alloc::Layout::new::<{ty}>()) }}
852 }}
853 "#
854 );
855 CppLayoutPolicy::HeapAllocated {
856 size_fn,
857 alloc_fn,
858 free_fn,
859 }
860 }
861 LayoutPolicy::OnlyByRef => CppLayoutPolicy::OnlyByRef,
862 }
863 }
864}