1 | #[cfg (feature = "napi6" )] |
2 | use std::convert::TryFrom; |
3 | #[cfg (feature = "napi5" )] |
4 | use std::ffi::c_void; |
5 | #[cfg (feature = "napi5" )] |
6 | use std::ptr; |
7 | |
8 | #[cfg (feature = "napi5" )] |
9 | use super::check_status; |
10 | use super::Value; |
11 | #[cfg (feature = "napi5" )] |
12 | use crate::sys; |
13 | #[cfg (feature = "napi5" )] |
14 | use crate::Env; |
15 | #[cfg (feature = "napi6" )] |
16 | use crate::Error; |
17 | #[cfg (feature = "napi5" )] |
18 | use crate::Result; |
19 | |
20 | pub struct JsObject(pub(crate) Value); |
21 | |
22 | #[cfg (feature = "napi5" )] |
23 | pub struct FinalizeContext<T: 'static, Hint: 'static> { |
24 | pub env: Env, |
25 | pub value: T, |
26 | pub hint: Hint, |
27 | } |
28 | |
29 | #[cfg (feature = "napi5" )] |
30 | impl 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" )] |
67 | unsafe 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" )] |
91 | pub enum KeyCollectionMode { |
92 | IncludePrototypes, |
93 | OwnOnly, |
94 | } |
95 | |
96 | #[cfg (feature = "napi6" )] |
97 | impl 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" )] |
113 | impl 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" )] |
123 | pub enum KeyFilter { |
124 | AllProperties, |
125 | Writable, |
126 | Enumerable, |
127 | Configurable, |
128 | SkipStrings, |
129 | SkipSymbols, |
130 | } |
131 | |
132 | #[cfg (feature = "napi6" )] |
133 | impl 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" )] |
153 | impl 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" )] |
167 | pub enum KeyConversion { |
168 | KeepNumbers, |
169 | NumbersToStrings, |
170 | } |
171 | |
172 | #[cfg (feature = "napi6" )] |
173 | impl 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" )] |
189 | impl 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 | |