| 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 | impl From<Value> for JsObject { |
| 22 | fn from(value: Value) -> Self { |
| 23 | Self(value) |
| 24 | } |
| 25 | } |
| 26 | |
| 27 | #[cfg (feature = "napi5" )] |
| 28 | pub struct FinalizeContext<T: 'static, Hint: 'static> { |
| 29 | pub env: Env, |
| 30 | pub value: T, |
| 31 | pub hint: Hint, |
| 32 | } |
| 33 | |
| 34 | #[cfg (feature = "napi5" )] |
| 35 | impl 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" )] |
| 72 | unsafe 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" )] |
| 96 | pub enum KeyCollectionMode { |
| 97 | IncludePrototypes, |
| 98 | OwnOnly, |
| 99 | } |
| 100 | |
| 101 | #[cfg (feature = "napi6" )] |
| 102 | impl 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" )] |
| 118 | impl 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" )] |
| 128 | pub enum KeyFilter { |
| 129 | AllProperties, |
| 130 | Writable, |
| 131 | Enumerable, |
| 132 | Configurable, |
| 133 | SkipStrings, |
| 134 | SkipSymbols, |
| 135 | } |
| 136 | |
| 137 | #[cfg (feature = "napi6" )] |
| 138 | impl 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" )] |
| 158 | impl 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" )] |
| 172 | pub enum KeyConversion { |
| 173 | KeepNumbers, |
| 174 | NumbersToStrings, |
| 175 | } |
| 176 | |
| 177 | #[cfg (feature = "napi6" )] |
| 178 | impl 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" )] |
| 194 | impl 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 | |