napi_h/js_values/
object.rs

1#[cfg(feature = "napi6")]
2use std::convert::TryFrom;
3#[cfg(feature = "napi5")]
4use std::ffi::c_void;
5#[cfg(feature = "napi5")]
6use std::ptr;
7
8#[cfg(feature = "napi5")]
9use super::check_status;
10use super::Value;
11#[cfg(feature = "napi5")]
12use crate::sys;
13#[cfg(feature = "napi5")]
14use crate::Env;
15#[cfg(feature = "napi6")]
16use crate::Error;
17#[cfg(feature = "napi5")]
18use crate::Result;
19
20pub struct JsObject(pub(crate) Value);
21
22#[cfg(feature = "napi5")]
23pub struct FinalizeContext<T: 'static, Hint: 'static> {
24  pub env: Env,
25  pub value: T,
26  pub hint: Hint,
27}
28
29#[cfg(feature = "napi5")]
30impl JsObject {
31  pub fn add_finalizer<T, Hint, F>(
32    &mut self,
33    native: T,
34    finalize_hint: Hint,
35    finalize_cb: F,
36  ) -> Result<()>
37  where
38    T: 'static,
39    Hint: 'static,
40    F: FnOnce(FinalizeContext<T, Hint>) + 'static,
41  {
42    let mut maybe_ref = ptr::null_mut();
43    let wrap_context = Box::leak(Box::new((native, finalize_cb, ptr::null_mut())));
44    check_status!(unsafe {
45      sys::napi_add_finalizer(
46        self.0.env,
47        self.0.value,
48        wrap_context as *mut _ as *mut c_void,
49        Some(
50          finalize_callback::<T, Hint, F>
51            as unsafe extern "C" fn(
52              env: sys::napi_env,
53              finalize_data: *mut c_void,
54              finalize_hint: *mut c_void,
55            ),
56        ),
57        Box::leak(Box::new(finalize_hint)) as *mut _ as *mut c_void,
58        &mut maybe_ref, // Note: this does not point to the boxed one…
59      )
60    })?;
61    wrap_context.2 = maybe_ref;
62    Ok(())
63  }
64}
65
66#[cfg(feature = "napi5")]
67unsafe extern "C" fn finalize_callback<T, Hint, F>(
68  raw_env: sys::napi_env,
69  finalize_data: *mut c_void,
70  finalize_hint: *mut c_void,
71) where
72  T: 'static,
73  Hint: 'static,
74  F: FnOnce(FinalizeContext<T, Hint>),
75{
76  let (value, callback, raw_ref) =
77    unsafe { *Box::from_raw(finalize_data as *mut (T, F, sys::napi_ref)) };
78  let hint = unsafe { *Box::from_raw(finalize_hint as *mut Hint) };
79  let env = unsafe { Env::from_raw(raw_env) };
80  callback(FinalizeContext { env, value, hint });
81  if !raw_ref.is_null() {
82    let status = unsafe { sys::napi_delete_reference(raw_env, raw_ref) };
83    debug_assert!(
84      status == sys::Status::napi_ok,
85      "Delete reference in finalize callback failed"
86    );
87  }
88}
89
90#[cfg(feature = "napi6")]
91pub enum KeyCollectionMode {
92  IncludePrototypes,
93  OwnOnly,
94}
95
96#[cfg(feature = "napi6")]
97impl TryFrom<sys::napi_key_collection_mode> for KeyCollectionMode {
98  type Error = Error;
99
100  fn try_from(value: sys::napi_key_collection_mode) -> Result<Self> {
101    match value {
102      sys::KeyCollectionMode::include_prototypes => Ok(Self::IncludePrototypes),
103      sys::KeyCollectionMode::own_only => Ok(Self::OwnOnly),
104      _ => Err(Error::new(
105        crate::Status::InvalidArg,
106        format!("Invalid key collection mode: {}", value),
107      )),
108    }
109  }
110}
111
112#[cfg(feature = "napi6")]
113impl From<KeyCollectionMode> for sys::napi_key_collection_mode {
114  fn from(value: KeyCollectionMode) -> Self {
115    match value {
116      KeyCollectionMode::IncludePrototypes => sys::KeyCollectionMode::include_prototypes,
117      KeyCollectionMode::OwnOnly => sys::KeyCollectionMode::own_only,
118    }
119  }
120}
121
122#[cfg(feature = "napi6")]
123pub enum KeyFilter {
124  AllProperties,
125  Writable,
126  Enumerable,
127  Configurable,
128  SkipStrings,
129  SkipSymbols,
130}
131
132#[cfg(feature = "napi6")]
133impl TryFrom<sys::napi_key_filter> for KeyFilter {
134  type Error = Error;
135
136  fn try_from(value: sys::napi_key_filter) -> Result<Self> {
137    match value {
138      sys::KeyFilter::all_properties => Ok(Self::AllProperties),
139      sys::KeyFilter::writable => Ok(Self::Writable),
140      sys::KeyFilter::enumerable => Ok(Self::Enumerable),
141      sys::KeyFilter::configurable => Ok(Self::Configurable),
142      sys::KeyFilter::skip_strings => Ok(Self::SkipStrings),
143      sys::KeyFilter::skip_symbols => Ok(Self::SkipSymbols),
144      _ => Err(Error::new(
145        crate::Status::InvalidArg,
146        format!("Invalid key filter [{}]", value),
147      )),
148    }
149  }
150}
151
152#[cfg(feature = "napi6")]
153impl From<KeyFilter> for sys::napi_key_filter {
154  fn from(value: KeyFilter) -> Self {
155    match value {
156      KeyFilter::AllProperties => sys::KeyFilter::all_properties,
157      KeyFilter::Writable => sys::KeyFilter::writable,
158      KeyFilter::Enumerable => sys::KeyFilter::enumerable,
159      KeyFilter::Configurable => sys::KeyFilter::configurable,
160      KeyFilter::SkipStrings => sys::KeyFilter::skip_strings,
161      KeyFilter::SkipSymbols => sys::KeyFilter::skip_symbols,
162    }
163  }
164}
165
166#[cfg(feature = "napi6")]
167pub enum KeyConversion {
168  KeepNumbers,
169  NumbersToStrings,
170}
171
172#[cfg(feature = "napi6")]
173impl TryFrom<sys::napi_key_conversion> for KeyConversion {
174  type Error = Error;
175
176  fn try_from(value: sys::napi_key_conversion) -> Result<Self> {
177    match value {
178      sys::KeyConversion::keep_numbers => Ok(Self::KeepNumbers),
179      sys::KeyConversion::numbers_to_strings => Ok(Self::NumbersToStrings),
180      _ => Err(Error::new(
181        crate::Status::InvalidArg,
182        format!("Invalid key conversion [{}]", value),
183      )),
184    }
185  }
186}
187
188#[cfg(feature = "napi6")]
189impl From<KeyConversion> for sys::napi_key_conversion {
190  fn from(value: KeyConversion) -> Self {
191    match value {
192      KeyConversion::KeepNumbers => sys::KeyConversion::keep_numbers,
193      KeyConversion::NumbersToStrings => sys::KeyConversion::numbers_to_strings,
194    }
195  }
196}