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