napi/bindgen_runtime/
mod.rs1use std::ffi::c_void;
2use std::sync::Arc;
3
4pub use callback_info::*;
5pub use class_accessor::*;
6pub use env::*;
7pub use iterator::Generator;
8pub use js_values::*;
9pub use module_register::*;
10pub use native_borrow::*;
11pub use type_tag::*;
12
13use super::sys;
14use crate::{Error, JsError, Result, Status};
15
16#[cfg(any(feature = "tokio_rt", feature = "async-runtime"))]
17pub mod async_iterator;
18#[cfg(any(feature = "tokio_rt", feature = "async-runtime"))]
19pub use async_iterator::AsyncGenerator;
20mod callback_info;
21mod class_accessor;
22mod env;
23mod error;
24pub mod iterator;
25mod js_values;
26mod module_register;
27mod native_borrow;
28mod type_tag;
29
30pub trait ObjectFinalize: Sized {
31 #[allow(unused)]
32 fn finalize(self, env: Env) -> Result<()> {
33 Ok(())
34 }
35}
36
37#[doc(hidden)]
38pub fn panic_to_error(e: Box<dyn std::any::Any + Send>) -> Error {
39 let message = {
40 if let Some(string) = e.downcast_ref::<String>() {
41 string.clone()
42 } else if let Some(string) = e.downcast_ref::<&str>() {
43 string.to_string()
44 } else {
45 format!("panic from Rust code: {:?}", e)
46 }
47 };
48 Error::new(Status::GenericFailure, message)
49}
50
51pub(crate) fn catch_unwind_safely(f: impl FnOnce()) {
52 if let Err(payload) = std::panic::catch_unwind(std::panic::AssertUnwindSafe(f)) {
53 std::mem::forget(payload);
56 }
57}
58
59#[doc(hidden)]
63pub(crate) unsafe extern "C" fn raw_finalize_unchecked<T: ObjectFinalize>(
64 env: sys::napi_env,
65 finalize_data: *mut c_void,
66 _finalize_hint: *mut c_void,
67) {
68 let data: Box<T> = unsafe { Box::from_raw(finalize_data.cast()) };
69 let ref_entry = REFERENCE_MAP
75 .with(|cell| cell.borrow_mut(|reference_map| reference_map.remove(&finalize_data)));
76 let finalize_result = data.finalize(Env::from_raw(env));
77
78 if let Some((_, ref_val, finalize_callbacks_ptr)) = ref_entry {
79 let finalize_callbacks_rc = unsafe { Arc::from_raw(finalize_callbacks_ptr) };
80
81 #[cfg(all(debug_assertions, not(target_family = "wasm")))]
82 {
83 let rc_strong_count = Arc::strong_count(&finalize_callbacks_rc);
84 if rc_strong_count != 1 && rc_strong_count != 2 {
88 eprintln!("Arc strong count is: {rc_strong_count}, it should be 1 or 2");
89 }
90 }
91 let finalize = unsafe { Box::from_raw(finalize_callbacks_rc.get()) };
92 finalize();
93 let delete_reference_status = unsafe { sys::napi_delete_reference(env, ref_val) };
94 debug_assert!(
95 delete_reference_status == sys::Status::napi_ok,
96 "Delete reference in finalize callback failed {}",
97 Status::from(delete_reference_status)
98 );
99 }
100
101 if let Err(err) = finalize_result {
102 let e: JsError = err.into();
103 unsafe { e.throw_into(env) };
104 }
105}
106
107#[doc(hidden)]
111pub unsafe extern "C" fn drop_buffer(
112 _env: sys::napi_env,
113 #[allow(unused)] finalize_data: *mut c_void,
114 finalize_hint: *mut c_void,
115) {
116 #[cfg(all(debug_assertions, not(windows), not(target_family = "wasm")))]
117 {
118 js_values::BUFFER_DATA.with(|buffer_data| {
119 let mut buffer = buffer_data.lock().expect("Unlock Buffer data failed");
120 buffer.remove(&(finalize_data as *mut u8));
121 });
122 }
123 unsafe {
124 drop(Box::from_raw(finalize_hint as *mut Buffer));
125 }
126}
127
128#[doc(hidden)]
132pub unsafe extern "C" fn drop_buffer_slice(
133 _env: sys::napi_env,
134 finalize_data: *mut c_void,
135 finalize_hint: *mut c_void,
136) {
137 let (len, cap): (usize, usize) = *unsafe { Box::from_raw(finalize_hint.cast()) };
138 #[cfg(all(debug_assertions, not(windows), not(target_family = "wasm")))]
139 {
140 js_values::BUFFER_DATA.with(|buffer_data| {
141 let mut buffer = buffer_data.lock().expect("Unlock Buffer data failed");
142 buffer.remove(&(finalize_data as *mut u8));
143 });
144 }
145 if finalize_data.is_null() {
146 return;
147 }
148 unsafe {
149 drop(Vec::from_raw_parts(finalize_data, len, cap));
150 }
151}
152
153#[doc(hidden)]
160#[cfg(not(feature = "noop"))]
161#[inline]
162pub unsafe fn create_object_with_properties(
163 env: sys::napi_env,
164 properties: &[sys::napi_property_descriptor],
165) -> Result<sys::napi_value> {
166 use crate::check_status;
167
168 let mut obj_ptr = std::ptr::null_mut();
169 check_status!(
170 sys::napi_create_object(env, &mut obj_ptr),
171 "Failed to create object",
172 )?;
173
174 if !properties.is_empty() {
175 check_status!(
176 sys::napi_define_properties(env, obj_ptr, properties.len(), properties.as_ptr()),
177 "Failed to define properties",
178 )?;
179 }
180
181 Ok(obj_ptr)
182}
183
184#[doc(hidden)]
185#[cfg(feature = "noop")]
186pub unsafe fn create_object_with_properties(
187 _env: sys::napi_env,
188 _properties: &[sys::napi_property_descriptor],
189) -> Result<sys::napi_value> {
190 Ok(std::ptr::null_mut())
191}
192
193#[cfg(test)]
194mod tests {
195 use std::panic::panic_any;
196
197 use super::catch_unwind_safely;
198
199 struct PanickingPanicPayload;
200
201 impl Drop for PanickingPanicPayload {
202 fn drop(&mut self) {
203 panic!("nested panic payload destructor");
204 }
205 }
206
207 #[test]
208 fn catch_unwind_safely_forgets_panicking_panic_payloads() {
209 catch_unwind_safely(|| panic_any(PanickingPanicPayload));
210 }
211}