emscripten_val/
bind.rs

1use emscripten_val_sys::bind::*;
2use std::ffi::CString;
3
4use crate::utils::get_type_id;
5pub use emscripten_val_sys::bind::_embind_register_class_property;
6
7pub fn register_class<T: 'static>(name: &str) {
8    let type_id = get_type_id::<T>();
9    let ptr_type_id = get_type_id::<*mut T>();
10    let const_ptr_type_id = get_type_id::<*const T>();
11    let name_cstr = CString::new(name).unwrap();
12
13    extern "C" fn get_actual_type<T: 'static>(_ptr: *const ()) -> crate::TYPEID {
14        get_type_id::<T>()
15    }
16
17    extern "C" fn upcast(ptr: *const ()) -> *const () {
18        ptr
19    }
20
21    extern "C" fn downcast(ptr: *const ()) -> *const () {
22        ptr
23    }
24
25    extern "C" fn destructor<T>(ptr: *mut T) {
26        unsafe {
27            let _ = Box::from_raw(ptr);
28        }
29    }
30
31    unsafe {
32        _embind_register_class(
33            type_id,
34            ptr_type_id,
35            const_ptr_type_id,
36            std::ptr::null() as _, // No base class
37            "pp\0".as_ptr() as _,
38            get_actual_type::<T> as _,
39            "pp\0".as_ptr() as _,
40            upcast as _,
41            "pp\0".as_ptr() as _,
42            downcast as _,
43            name_cstr.as_ptr(),
44            "vp\0".as_ptr() as _,
45            destructor::<T> as _,
46        );
47    }
48}
49
50pub fn register_class_default_constructor<T: 'static + Default>() {
51    extern "C" fn invoker<T: Default>(ptr: *const ()) -> *mut T {
52        let ptr: fn() -> T = unsafe { std::mem::transmute(ptr) };
53        let obj = Box::new(ptr());
54        Box::into_raw(obj) as _
55    }
56
57    unsafe {
58        let arg_types = [get_type_id::<*mut T>()];
59        _embind_register_class_constructor(
60            get_type_id::<T>(),
61            arg_types.len() as u32,
62            arg_types.as_ptr() as _,
63            "pp\0".as_ptr() as _,
64            invoker::<T> as _,
65            T::default as _,
66        )
67    }
68}
69
70#[macro_export]
71macro_rules! register_class_property {
72    ($cls:ty, $name:literal, $member:ident, $membertype:ty) => {{
73        let f = || unsafe {
74            extern "C" fn getter(_ctx: *mut (), ptr: *const $cls) -> $membertype {
75                unsafe { (*ptr).$member }
76            }
77
78            extern "C" fn setter(_ctx: *mut (), ptr: *mut $cls, value: $membertype) {
79                unsafe { (*ptr).$member = value; }
80            }
81
82            let cname = std::ffi::CString::new($name).unwrap();
83
84            let getter_signature = concat!(
85                stringify!(<$membertype>::signature()),
86                "pp\0"
87            );
88
89            let setter_signature = concat!(
90                "vpp",
91                stringify!(<$membertype>::signature()),
92                "\0"
93            );
94
95            _embind_register_class_property(
96                $crate::utils::get_type_id::<$cls>(),
97                cname.as_ptr(),
98                <$membertype>::id(),
99                getter_signature.as_ptr() as _,
100                getter as _,
101                std::ptr::null_mut(),
102                <$membertype>::id(),
103                setter_signature.as_ptr() as _,
104                setter as _,
105                std::ptr::null_mut(),
106            );
107        };
108        f();
109    }};
110}