zngur_generator/
rust.rs

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}