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: T, callback: F, raw_ref: *mut napi_ref__) =
77 unsafe { *Box::from_raw(finalize_data as *mut (T, F, sys::napi_ref)) };
78 let hint: Hint = unsafe { *Box::from_raw(finalize_hint as *mut Hint) };
79 let env: Env = unsafe { Env::from_raw(raw_env) };
80 callback(FinalizeContext { env, value, hint });
81 if !raw_ref.is_null() {
82 let status: i32 = unsafe { sys::napi_delete_reference(raw_env, ref_: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 reason: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 reason: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 reason: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}
197