napi/js_values/
object.rs

1#[cfg(feature = "napi5")]
2use std::ffi::c_void;
3#[cfg(feature = "napi5")]
4use std::ptr;
5
6#[cfg(feature = "napi5")]
7use super::check_status;
8use crate::{
9  bindgen_prelude::{FromNapiValue, ToNapiValue, TypeName, ValidateNapiValue},
10  sys, Result, Value, ValueType,
11};
12#[cfg(feature = "napi5")]
13use crate::{bindgen_runtime::FinalizeContext, Env};
14
15#[deprecated(since = "3.0.0", note = "Use `napi::bindgen_prelude::Object` instead")]
16#[derive(Clone, Copy)]
17pub struct JsObject(pub(crate) Value);
18
19impl TypeName for JsObject {
20  fn type_name() -> &'static str {
21    "Object"
22  }
23
24  fn value_type() -> ValueType {
25    ValueType::Object
26  }
27}
28
29impl ValidateNapiValue for JsObject {}
30
31impl FromNapiValue for JsObject {
32  unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
33    Ok(Self(Value {
34      env,
35      value: napi_val,
36      value_type: ValueType::Object,
37    }))
38  }
39}
40
41impl ToNapiValue for JsObject {
42  unsafe fn to_napi_value(_: sys::napi_env, value: Self) -> Result<sys::napi_value> {
43    Ok(value.0.value)
44  }
45}
46
47impl From<Value> for JsObject {
48  fn from(value: Value) -> Self {
49    Self(value)
50  }
51}
52
53#[cfg(feature = "napi5")]
54impl JsObject {
55  pub fn add_finalizer<T, Hint, F>(
56    &mut self,
57    native: T,
58    finalize_hint: Hint,
59    finalize_cb: F,
60  ) -> Result<()>
61  where
62    T: 'static,
63    Hint: 'static,
64    F: FnOnce(FinalizeContext<T, Hint>) + 'static,
65  {
66    let mut maybe_ref = ptr::null_mut();
67    let wrap_context = Box::leak(Box::new((native, finalize_cb, ptr::null_mut())));
68    check_status!(unsafe {
69      sys::napi_add_finalizer(
70        self.0.env,
71        self.0.value,
72        wrap_context as *mut _ as *mut c_void,
73        Some(
74          finalize_callback::<T, Hint, F>
75            as unsafe extern "C" fn(
76              env: sys::napi_env,
77              finalize_data: *mut c_void,
78              finalize_hint: *mut c_void,
79            ),
80        ),
81        Box::leak(Box::new(finalize_hint)) as *mut _ as *mut c_void,
82        &mut maybe_ref, // Note: this does not point to the boxed one…
83      )
84    })?;
85    wrap_context.2 = maybe_ref;
86    Ok(())
87  }
88}
89
90#[cfg(feature = "napi5")]
91unsafe extern "C" fn finalize_callback<T, Hint, F>(
92  raw_env: sys::napi_env,
93  finalize_data: *mut c_void,
94  finalize_hint: *mut c_void,
95) where
96  T: 'static,
97  Hint: 'static,
98  F: FnOnce(FinalizeContext<T, Hint>),
99{
100  let (value, callback, raw_ref) =
101    unsafe { *Box::from_raw(finalize_data as *mut (T, F, sys::napi_ref)) };
102  let hint = unsafe { *Box::from_raw(finalize_hint as *mut Hint) };
103  let env = Env::from_raw(raw_env);
104  callback(FinalizeContext { env, value, hint });
105  if !raw_ref.is_null() {
106    let status = unsafe { sys::napi_delete_reference(raw_env, raw_ref) };
107    debug_assert!(
108      status == sys::Status::napi_ok,
109      "Delete reference in finalize callback failed"
110    );
111  }
112}