1use std::{mem::MaybeUninit, os::raw::c_void, ptr};
4
5use super::{
6 bindings as napi,
7 raw::{Env, Local},
8};
9
10pub unsafe fn new<F>(env: Env, name: &str, callback: F) -> Result<Local, napi::Status>
11where
12 F: Fn(Env, napi::CallbackInfo) -> Local + 'static,
13{
14 let mut out = MaybeUninit::uninit();
15 let data = Box::into_raw(Box::new(callback));
16 let status = napi::create_function(
17 env,
18 name.as_ptr().cast(),
19 name.len(),
20 Some(call_boxed::<F>),
21 data.cast(),
22 out.as_mut_ptr(),
23 );
24
25 match status {
26 Err(err @ napi::Status::PendingException) => {
27 drop(Box::from_raw(data));
28
29 return Err(err);
30 }
31 status => status.unwrap(),
32 };
33
34 let out = out.assume_init();
35
36 #[cfg(feature = "napi-5")]
37 {
38 unsafe extern "C" fn drop_function<F>(
39 _env: Env,
40 _finalize_data: *mut c_void,
41 finalize_hint: *mut c_void,
42 ) {
43 drop(Box::from_raw(finalize_hint.cast::<F>()));
44 }
45
46 let status = napi::add_finalizer(
47 env,
48 out,
49 ptr::null_mut(),
50 Some(drop_function::<F>),
51 data.cast(),
52 ptr::null_mut(),
53 );
54
55 status.unwrap();
59 }
60
61 Ok(out)
62}
63
64unsafe extern "C" fn call_boxed<F>(env: Env, info: napi::CallbackInfo) -> Local
67where
68 F: Fn(Env, napi::CallbackInfo) -> Local + 'static,
69{
70 let mut data = MaybeUninit::uninit();
71 napi::get_cb_info(
72 env,
73 info,
74 ptr::null_mut(),
75 ptr::null_mut(),
76 ptr::null_mut(),
77 data.as_mut_ptr(),
78 )
79 .unwrap();
80
81 let callback = &*data.assume_init().cast::<F>();
82
83 callback(env, info)
84}
85
86pub unsafe fn construct(
87 out: &mut Local,
88 env: Env,
89 fun: Local,
90 argc: usize,
91 argv: *const c_void,
92) -> bool {
93 let status = napi::new_instance(env, fun, argc, argv as *const _, out as *mut _);
94
95 status.is_ok()
96}