1use std::any::{type_name, TypeId};
2#[cfg(feature = "napi6")]
3use std::convert::TryFrom;
4use std::ffi::{c_void, CStr, CString};
5use std::marker::PhantomData;
6use std::ptr;
7
8use crate::{
9 bindgen_prelude::*, check_status, raw_finalize, sys, type_of, Callback, TaggedObject, Value,
10};
11#[cfg(feature = "napi5")]
12use crate::{Env, PropertyClosures};
13
14pub trait JsObjectValue<'env>: JsValue<'env> {
15 fn set_property<'k, 'v, K, V>(&mut self, key: K, value: V) -> Result<()>
17 where
18 K: JsValue<'k>,
19 V: JsValue<'v>,
20 {
21 let env = self.value().env;
22 check_status!(unsafe {
23 sys::napi_set_property(env, self.value().value, key.raw(), value.raw())
24 })
25 }
26
27 fn get_property<'k, K, T>(&self, key: K) -> Result<T>
31 where
32 K: JsValue<'k>,
33 T: FromNapiValue + ValidateNapiValue,
34 {
35 let mut raw_value = ptr::null_mut();
36 let env = self.value().env;
37 check_status!(unsafe {
38 sys::napi_get_property(env, self.value().value, key.raw(), &mut raw_value)
39 })?;
40 unsafe { T::validate(env, raw_value) }.map_err(|mut err| {
41 err.reason = format!(
42 "Object property '{:?}' type mismatch. {}",
43 key
44 .coerce_to_string()
45 .and_then(|s| s.into_utf8())
46 .and_then(|s| s.into_owned()),
47 err.reason
48 );
49 err
50 })?;
51 unsafe { T::from_napi_value(env, raw_value) }
52 }
53
54 fn get_property_unchecked<'k, K, T>(&self, key: K) -> Result<T>
56 where
57 K: JsValue<'k>,
58 T: FromNapiValue,
59 {
60 let mut raw_value = ptr::null_mut();
61 let env = self.value().env;
62 check_status!(unsafe {
63 sys::napi_get_property(env, self.value().value, key.raw(), &mut raw_value)
64 })?;
65 unsafe { T::from_napi_value(env, raw_value) }
66 }
67
68 fn set_named_property<T>(&mut self, name: &str, value: T) -> Result<()>
70 where
71 T: ToNapiValue,
72 {
73 let key = CString::new(name)?;
74 let env = self.value().env;
75 check_status!(unsafe {
76 sys::napi_set_named_property(env, self.raw(), key.as_ptr(), T::to_napi_value(env, value)?)
77 })
78 }
79
80 fn set_c_named_property<T>(&mut self, name: &CStr, value: T) -> Result<()>
83 where
84 T: ToNapiValue,
85 {
86 let env = self.value().env;
87 check_status!(unsafe {
88 sys::napi_set_named_property(
89 env,
90 self.raw(),
91 name.as_ptr(),
92 T::to_napi_value(env, value)?,
93 )
94 })
95 }
96
97 fn create_named_method<K>(&mut self, name: K, function: Callback) -> Result<()>
99 where
100 K: AsRef<str>,
101 {
102 let mut js_function = ptr::null_mut();
103 let len = name.as_ref().len();
104 let name = CString::new(name.as_ref())?;
105 let env = self.value().env;
106 check_status!(unsafe {
107 sys::napi_create_function(
108 env,
109 name.as_ptr(),
110 len as isize,
111 Some(function),
112 ptr::null_mut(),
113 &mut js_function,
114 )
115 })?;
116 check_status!(
117 unsafe { sys::napi_set_named_property(env, self.value().value, name.as_ptr(), js_function) },
118 "create_named_method error"
119 )
120 }
121
122 fn create_c_named_method(&mut self, name: &CStr, function: Callback) -> Result<()> {
125 let mut js_function = ptr::null_mut();
126 let len = name.count_bytes();
127 let env = self.value().env;
128 check_status!(unsafe {
129 sys::napi_create_function(
130 env,
131 name.as_ptr(),
132 len as isize,
133 Some(function),
134 ptr::null_mut(),
135 &mut js_function,
136 )
137 })?;
138 check_status!(
139 unsafe { sys::napi_set_named_property(env, self.value().value, name.as_ptr(), js_function) },
140 "create_named_method error"
141 )
142 }
143
144 fn get_named_property<T>(&self, name: &str) -> Result<T>
148 where
149 T: FromNapiValue + ValidateNapiValue,
150 {
151 let key = CString::new(name)?;
152 let mut raw_value = ptr::null_mut();
153 let env = self.value().env;
154 check_status!(
155 unsafe {
156 sys::napi_get_named_property(env, self.value().value, key.as_ptr(), &mut raw_value)
157 },
158 "get_named_property error"
159 )?;
160 unsafe { <T as ValidateNapiValue>::validate(env, raw_value) }.map_err(|mut err| {
161 err.reason = format!("Object property '{name}' type mismatch. {}", err.reason);
162 err
163 })?;
164 unsafe { <T as FromNapiValue>::from_napi_value(env, raw_value) }
165 }
166
167 fn get_c_named_property<T>(&self, name: &CStr) -> Result<T>
173 where
174 T: FromNapiValue + ValidateNapiValue,
175 {
176 let mut raw_value = ptr::null_mut();
177 let env = self.value().env;
178 check_status!(
179 unsafe {
180 sys::napi_get_named_property(env, self.value().value, name.as_ptr(), &mut raw_value)
181 },
182 "get_named_property error"
183 )?;
184 unsafe { <T as ValidateNapiValue>::validate(env, raw_value) }.map_err(|mut err| {
185 err.reason = format!(
186 "Object property '{}' type mismatch. {}",
187 name.to_string_lossy(),
188 err.reason
189 );
190 err
191 })?;
192 unsafe { <T as FromNapiValue>::from_napi_value(env, raw_value) }
193 }
194
195 fn get_named_property_unchecked<T>(&self, name: &str) -> Result<T>
197 where
198 T: FromNapiValue,
199 {
200 let key = CString::new(name)?;
201 let mut raw_value = ptr::null_mut();
202 let env = self.value().env;
203 check_status!(
204 unsafe {
205 sys::napi_get_named_property(env, self.value().value, key.as_ptr(), &mut raw_value)
206 },
207 "get_named_property_unchecked error"
208 )?;
209 unsafe { <T as FromNapiValue>::from_napi_value(env, raw_value) }
210 }
211
212 fn get_c_named_property_unchecked<T>(&self, name: &CStr) -> Result<T>
216 where
217 T: FromNapiValue,
218 {
219 let mut raw_value = ptr::null_mut();
220 let env = self.value().env;
221 check_status!(
222 unsafe {
223 sys::napi_get_named_property(env, self.value().value, name.as_ptr(), &mut raw_value)
224 },
225 "get_c_named_property_unchecked error"
226 )?;
227 unsafe { <T as FromNapiValue>::from_napi_value(env, raw_value) }
228 }
229
230 fn has_named_property<N: AsRef<str>>(&self, name: N) -> Result<bool> {
232 let mut result = false;
233 let key = CString::new(name.as_ref())?;
234 let env = self.value().env;
235 check_status!(
236 unsafe { sys::napi_has_named_property(env, self.value().value, key.as_ptr(), &mut result) },
237 "has_named_property error"
238 )?;
239 Ok(result)
240 }
241
242 fn has_c_named_property(&self, name: &CStr) -> Result<bool> {
246 let mut result = false;
247 let env = self.value().env;
248 check_status!(
249 unsafe { sys::napi_has_named_property(env, self.value().value, name.as_ptr(), &mut result) },
250 "has_c_named_property error"
251 )?;
252 Ok(result)
253 }
254
255 fn delete_property<'s, S>(&mut self, name: S) -> Result<bool>
257 where
258 S: JsValue<'s>,
259 {
260 let mut result = false;
261 let env = self.value().env;
262 check_status!(unsafe {
263 sys::napi_delete_property(env, self.value().value, name.raw(), &mut result)
264 })?;
265 Ok(result)
266 }
267
268 fn delete_named_property<K: AsRef<str>>(&mut self, name: K) -> Result<bool> {
270 let name = name.as_ref();
271 let mut result = false;
272 let mut js_key = ptr::null_mut();
273 let env = self.value().env;
274 check_status!(unsafe {
275 sys::napi_create_string_utf8(env, name.as_ptr().cast(), name.len() as isize, &mut js_key)
276 })?;
277 check_status!(unsafe {
278 sys::napi_delete_property(env, self.value().value, js_key, &mut result)
279 })?;
280 Ok(result)
281 }
282
283 fn delete_c_named_property(&mut self, name: &CStr) -> Result<bool> {
287 let mut result = false;
288 let mut js_key = ptr::null_mut();
289 let env = self.value().env;
290 check_status!(unsafe {
291 sys::napi_create_string_utf8(env, name.as_ptr(), name.count_bytes() as isize, &mut js_key)
292 })?;
293 check_status!(unsafe {
294 sys::napi_delete_property(env, self.value().value, js_key, &mut result)
295 })?;
296 Ok(result)
297 }
298
299 fn has_own_property(&self, key: &str) -> Result<bool> {
301 let mut result = false;
302 let mut js_key = ptr::null_mut();
303 let env = self.value().env;
304 check_status!(unsafe {
305 sys::napi_create_string_utf8(env, key.as_ptr().cast(), key.len() as isize, &mut js_key)
306 })?;
307 check_status!(unsafe {
308 sys::napi_has_own_property(env, self.value().value, js_key, &mut result)
309 })?;
310 Ok(result)
311 }
312
313 fn has_c_own_property(&self, key: &CStr) -> Result<bool> {
317 let mut result = false;
318 let mut js_key = ptr::null_mut();
319 let env = self.value().env;
320 check_status!(unsafe {
321 sys::napi_create_string_utf8(env, key.as_ptr(), key.count_bytes() as isize, &mut js_key)
322 })?;
323 check_status!(unsafe {
324 sys::napi_has_own_property(env, self.value().value, js_key, &mut result)
325 })?;
326 Ok(result)
327 }
328
329 fn has_own_property_js<'k, K>(&self, key: K) -> Result<bool>
331 where
332 K: JsValue<'k>,
333 {
334 let mut result = false;
335 let env = self.value().env;
336 check_status!(unsafe {
337 sys::napi_has_own_property(env, self.value().value, key.raw(), &mut result)
338 })?;
339 Ok(result)
340 }
341
342 fn has_property(&self, name: &str) -> Result<bool> {
344 let mut js_key = ptr::null_mut();
345 let mut result = false;
346 let env = self.value().env;
347 check_status!(unsafe {
348 sys::napi_create_string_utf8(env, name.as_ptr().cast(), name.len() as isize, &mut js_key)
349 })?;
350 check_status!(unsafe { sys::napi_has_property(env, self.value().value, js_key, &mut result) })?;
351 Ok(result)
352 }
353
354 fn has_property_js<'k, K>(&self, name: K) -> Result<bool>
357 where
358 K: JsValue<'k>,
359 {
360 let mut result = false;
361 let env = self.value().env;
362 check_status!(unsafe {
363 sys::napi_has_property(env, self.value().value, name.raw(), &mut result)
364 })?;
365 Ok(result)
366 }
367
368 fn get_property_names(&self) -> Result<Object<'env>> {
371 let mut raw_value = ptr::null_mut();
372 let env = self.value().env;
373 check_status!(unsafe {
374 sys::napi_get_property_names(env, self.value().value, &mut raw_value)
375 })?;
376 Ok(Object::from_raw(env, raw_value))
377 }
378
379 #[cfg(feature = "napi6")]
380 fn get_all_property_names(
383 &self,
384 mode: KeyCollectionMode,
385 filter: KeyFilter,
386 conversion: KeyConversion,
387 ) -> Result<Object<'env>> {
388 let mut properties_value = ptr::null_mut();
389 let env = self.value().env;
390 check_status!(unsafe {
391 sys::napi_get_all_property_names(
392 env,
393 self.value().value,
394 mode.into(),
395 filter.into(),
396 conversion.into(),
397 &mut properties_value,
398 )
399 })?;
400 Ok(Object::from_raw(env, properties_value))
401 }
402
403 fn get_prototype(&self) -> Result<Unknown<'env>> {
405 let mut result = ptr::null_mut();
406 let env = self.value().env;
407 check_status!(unsafe { sys::napi_get_prototype(env, self.value().value, &mut result) })?;
408 Ok(unsafe { Unknown::from_raw_unchecked(env, result) })
409 }
410
411 fn get_prototype_unchecked<T>(&self) -> Result<T>
413 where
414 T: FromNapiValue,
415 {
416 let mut result = ptr::null_mut();
417 let env = self.value().env;
418 check_status!(unsafe { sys::napi_get_prototype(env, self.value().value, &mut result) })?;
419 unsafe { T::from_napi_value(env, result) }
420 }
421
422 fn set_element<'t, T>(&mut self, index: u32, value: T) -> Result<()>
424 where
425 T: JsValue<'t>,
426 {
427 let env = self.value().env;
428 check_status!(unsafe { sys::napi_set_element(env, self.value().value, index, value.raw()) })
429 }
430
431 fn has_element(&self, index: u32) -> Result<bool> {
433 let mut result = false;
434 let env = self.value().env;
435 check_status!(unsafe { sys::napi_has_element(env, self.value().value, index, &mut result) })?;
436 Ok(result)
437 }
438
439 fn delete_element(&mut self, index: u32) -> Result<bool> {
441 let mut result = false;
442 let env = self.value().env;
443 check_status!(unsafe {
444 sys::napi_delete_element(env, self.value().value, index, &mut result)
445 })?;
446 Ok(result)
447 }
448
449 fn get_element<T>(&self, index: u32) -> Result<T>
453 where
454 T: FromNapiValue,
455 {
456 let mut raw_value = ptr::null_mut();
457 let env = self.value().env;
458 check_status!(unsafe {
459 sys::napi_get_element(env, self.value().value, index, &mut raw_value)
460 })?;
461 unsafe { T::from_napi_value(env, raw_value) }
462 }
463
464 fn define_properties(&mut self, properties: &[Property]) -> Result<()> {
466 let properties_iter = properties.iter().map(|property| property.raw());
467 let env = self.value().env;
468 #[cfg(feature = "napi5")]
469 {
470 if !properties.is_empty() {
471 let mut closures = properties_iter
472 .clone()
473 .map(|p| p.data)
474 .filter(|data| !data.is_null())
475 .collect::<Vec<*mut std::ffi::c_void>>();
476 if !closures.is_empty() {
477 let finalize_hint = Box::into_raw(Box::new((closures.len(), closures.capacity())));
478 check_status!(
479 unsafe {
480 sys::napi_add_finalizer(
481 env,
482 self.value().value,
483 closures.as_mut_ptr().cast(),
484 Some(finalize_closures),
485 finalize_hint.cast(),
486 ptr::null_mut(),
487 )
488 },
489 "Failed to add finalizer"
490 )?;
491 std::mem::forget(closures);
492 }
493 }
494 }
495 check_status!(unsafe {
496 sys::napi_define_properties(
497 env,
498 self.value().value,
499 properties.len(),
500 properties_iter
501 .collect::<Vec<sys::napi_property_descriptor>>()
502 .as_ptr(),
503 )
504 })
505 }
506
507 fn get_array_length(&self) -> Result<u32> {
511 if !(self.is_array()?) {
512 return Err(Error::new(
513 Status::ArrayExpected,
514 "Object is not array".to_owned(),
515 ));
516 }
517 self.get_array_length_unchecked()
518 }
519
520 fn get_array_length_unchecked(&self) -> Result<u32> {
522 let mut length: u32 = 0;
523 let env = self.value().env;
524 check_status!(unsafe { sys::napi_get_array_length(env, self.value().value, &mut length) })?;
525 Ok(length)
526 }
527
528 fn wrap<T: 'static>(&mut self, native_object: T, size_hint: Option<usize>) -> Result<()> {
531 let env = self.value().env;
532 let value = self.raw();
533 check_status!(unsafe {
534 sys::napi_wrap(
535 env,
536 value,
537 Box::into_raw(Box::new(TaggedObject::new(native_object))).cast(),
538 Some(raw_finalize::<TaggedObject<T>>),
539 Box::into_raw(Box::new(size_hint.unwrap_or(0) as i64)).cast(),
540 ptr::null_mut(),
541 )
542 })
543 }
544
545 #[allow(clippy::mut_from_ref)]
549 fn unwrap<T: 'static>(&self) -> Result<&mut T> {
550 let env = self.value().env;
551 let value = self.raw();
552 unsafe {
553 let mut unknown_tagged_object: *mut c_void = ptr::null_mut();
554 check_status!(
555 sys::napi_unwrap(env, value, &mut unknown_tagged_object),
556 "Failed to unwrap value of the Object"
557 )?;
558
559 let type_id = unknown_tagged_object as *const TypeId;
560 if *type_id == TypeId::of::<T>() {
561 let tagged_object = unknown_tagged_object as *mut TaggedObject<T>;
562 (*tagged_object).object.as_mut().ok_or_else(|| {
563 Error::new(
564 Status::InvalidArg,
565 "Invalid argument, nothing attach to js_object".to_owned(),
566 )
567 })
568 } else {
569 Err(Error::new(
570 Status::InvalidArg,
571 format!(
572 "Invalid argument, {} on unwrap is not the type of wrapped object",
573 type_name::<T>()
574 ),
575 ))
576 }
577 }
578 }
579
580 fn remove_wrapped<T: 'static>(&mut self) -> Result<()> {
584 let env = self.value().env;
585 let value = self.raw();
586 unsafe {
587 let mut unknown_tagged_object = ptr::null_mut();
588 check_status!(sys::napi_remove_wrap(
589 env,
590 value,
591 &mut unknown_tagged_object,
592 ))?;
593 let type_id = unknown_tagged_object as *const TypeId;
594 if *type_id == TypeId::of::<T>() {
595 drop(Box::from_raw(unknown_tagged_object as *mut TaggedObject<T>));
596 Ok(())
597 } else {
598 Err(Error::new(
599 Status::InvalidArg,
600 format!(
601 "Invalid argument, {} on unwrap is not the type of wrapped object",
602 type_name::<T>()
603 ),
604 ))
605 }
606 }
607 }
608
609 #[cfg(feature = "napi5")]
610 fn add_finalizer<T, Hint, F>(
614 &mut self,
615 native: T,
616 finalize_hint: Hint,
617 finalize_cb: F,
618 ) -> Result<()>
619 where
620 T: 'static,
621 Hint: 'static,
622 F: FnOnce(FinalizeContext<T, Hint>) + 'static,
623 {
624 let mut maybe_ref = ptr::null_mut();
625 let env = self.value().env;
626 let value = self.raw();
627 let wrap_context = Box::leak(Box::new((native, finalize_cb, ptr::null_mut())));
628 check_status!(unsafe {
629 sys::napi_add_finalizer(
630 env,
631 value,
632 (wrap_context as *mut (T, F, sys::napi_ref)).cast(),
633 Some(finalize_callback::<T, Hint, F>),
634 Box::into_raw(Box::new(finalize_hint)).cast(),
635 &mut maybe_ref, )
637 })?;
638 wrap_context.2 = maybe_ref;
639 Ok(())
640 }
641
642 #[cfg(feature = "napi8")]
643 fn freeze(&mut self) -> Result<()> {
647 let env = self.value().env;
648 check_status!(unsafe { sys::napi_object_freeze(env, self.value().value) })
649 }
650
651 #[cfg(feature = "napi8")]
652 fn seal(&mut self) -> Result<()> {
655 let env = self.value().env;
656 check_status!(unsafe { sys::napi_object_seal(env, self.value().value) })
657 }
658}
659
660#[derive(Clone, Copy)]
661pub struct Object<'env>(pub(crate) Value, pub(crate) PhantomData<&'env ()>);
662
663impl<'env> JsValue<'env> for Object<'env> {
664 fn value(&self) -> Value {
665 self.0
666 }
667}
668
669impl<'env> JsObjectValue<'env> for Object<'env> {}
670
671impl TypeName for Object<'_> {
672 fn type_name() -> &'static str {
673 "Object"
674 }
675
676 fn value_type() -> ValueType {
677 ValueType::Object
678 }
679}
680
681impl ValidateNapiValue for Object<'_> {}
682
683impl FromNapiValue for Object<'_> {
684 unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
685 Ok(Self(
686 Value {
687 env,
688 value: napi_val,
689 value_type: ValueType::Object,
690 },
691 PhantomData,
692 ))
693 }
694}
695
696impl ToNapiValue for &Object<'_> {
697 unsafe fn to_napi_value(_env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
698 Ok(val.0.value)
699 }
700}
701
702impl Object<'_> {
703 pub fn from_raw(env: sys::napi_env, value: sys::napi_value) -> Self {
705 Self(
706 Value {
707 env,
708 value,
709 value_type: ValueType::Object,
710 },
711 PhantomData,
712 )
713 }
714
715 pub fn new(env: &Env) -> Result<Self> {
717 let mut ptr = ptr::null_mut();
718 unsafe {
719 check_status!(
720 sys::napi_create_object(env.0, &mut ptr),
721 "Failed to create napi Object"
722 )?;
723 }
724
725 Ok(Self(
726 crate::Value {
727 env: env.0,
728 value: ptr,
729 value_type: ValueType::Object,
730 },
731 PhantomData,
732 ))
733 }
734
735 pub fn get<V: FromNapiValue>(&self, field: &str) -> Result<Option<V>> {
737 unsafe {
738 self
739 .get_inner(field)?
740 .map(|v| V::from_napi_value(self.0.env, v))
741 .transpose()
742 }
743 }
744
745 fn get_inner(&self, field: &str) -> Result<Option<sys::napi_value>> {
746 unsafe {
747 let mut property_key = std::ptr::null_mut();
748 check_status!(
749 sys::napi_create_string_utf8(
750 self.0.env,
751 field.as_ptr().cast(),
752 field.len() as isize,
753 &mut property_key,
754 ),
755 "Failed to create property key with `{field}`"
756 )?;
757
758 let mut ret = ptr::null_mut();
759
760 check_status!(
761 sys::napi_get_property(self.0.env, self.0.value, property_key, &mut ret),
762 "Failed to get property with field `{field}`",
763 )?;
764
765 let ty = type_of!(self.0.env, ret)?;
766
767 Ok(if ty == ValueType::Undefined {
768 None
769 } else {
770 Some(ret)
771 })
772 }
773 }
774
775 pub fn set<K: AsRef<str>, V: ToNapiValue>(&mut self, field: K, val: V) -> Result<()> {
777 unsafe { self.set_inner(field.as_ref(), V::to_napi_value(self.0.env, val)?) }
778 }
779
780 unsafe fn set_inner(&mut self, field: &str, napi_val: sys::napi_value) -> Result<()> {
781 let mut property_key = std::ptr::null_mut();
782 check_status!(
783 unsafe {
784 sys::napi_create_string_utf8(
785 self.0.env,
786 field.as_ptr().cast(),
787 field.len() as isize,
788 &mut property_key,
789 )
790 },
791 "Failed to create property key with `{field}`"
792 )?;
793
794 check_status!(
795 unsafe { sys::napi_set_property(self.0.env, self.0.value, property_key, napi_val) },
796 "Failed to set property with field `{field}`"
797 )?;
798 Ok(())
799 }
800
801 pub fn keys(obj: &Object) -> Result<Vec<String>> {
803 let mut names = ptr::null_mut();
804 unsafe {
805 check_status!(
806 sys::napi_get_property_names(obj.0.env, obj.0.value, &mut names),
807 "Failed to get property names of given object"
808 )?;
809 }
810
811 let names = unsafe { Array::from_napi_value(obj.0.env, names)? };
812 let mut ret = vec![];
813
814 for i in 0..names.len() {
815 ret.push(names.get_element::<String>(i)?);
816 }
817
818 Ok(ret)
819 }
820
821 pub fn create_ref<const LEAK_CHECK: bool>(&self) -> Result<ObjectRef<LEAK_CHECK>> {
825 let mut ref_ = ptr::null_mut();
826 check_status!(
827 unsafe { sys::napi_create_reference(self.0.env, self.0.value, 1, &mut ref_) },
828 "Failed to create reference"
829 )?;
830 Ok(ObjectRef { inner: ref_ })
831 }
832}
833
834pub struct ObjectRef<const LEAK_CHECK: bool = true> {
840 pub(crate) inner: sys::napi_ref,
841}
842
843unsafe impl<const LEAK_CHECK: bool> Send for ObjectRef<LEAK_CHECK> {}
844
845impl<const LEAK_CHECK: bool> Drop for ObjectRef<LEAK_CHECK> {
846 fn drop(&mut self) {
847 if LEAK_CHECK && !self.inner.is_null() {
848 eprintln!("ObjectRef is not unref, it considered as a memory leak");
849 }
850 }
851}
852
853impl<const LEAK_CHECK: bool> ObjectRef<LEAK_CHECK> {
854 pub fn get_value<'env>(&self, env: &'env Env) -> Result<Object<'env>> {
856 let mut result = ptr::null_mut();
857 check_status!(
858 unsafe { sys::napi_get_reference_value(env.0, self.inner, &mut result) },
859 "Failed to get reference value"
860 )?;
861 Ok(Object::from_raw(env.0, result))
862 }
863
864 pub fn unref(mut self, env: &Env) -> Result<()> {
866 check_status!(
867 unsafe { sys::napi_delete_reference(env.0, self.inner) },
868 "delete Ref failed"
869 )?;
870 self.inner = ptr::null_mut();
871 Ok(())
872 }
873}
874
875impl<const LEAK_CHECK: bool> FromNapiValue for ObjectRef<LEAK_CHECK> {
876 unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
877 let mut ref_ = ptr::null_mut();
878 check_status!(
879 unsafe { sys::napi_create_reference(env, napi_val, 1, &mut ref_) },
880 "Failed to create reference"
881 )?;
882 Ok(Self { inner: ref_ })
883 }
884}
885
886impl<const LEAK_CHECK: bool> ToNapiValue for &ObjectRef<LEAK_CHECK> {
887 unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
888 let mut result = ptr::null_mut();
889 check_status!(
890 unsafe { sys::napi_get_reference_value(env, val.inner, &mut result) },
891 "Failed to get reference value"
892 )?;
893 Ok(result)
894 }
895}
896
897impl<const LEAK_CHECK: bool> ToNapiValue for ObjectRef<LEAK_CHECK> {
898 unsafe fn to_napi_value(env: sys::napi_env, mut val: Self) -> Result<sys::napi_value> {
899 let mut result = ptr::null_mut();
900 check_status!(
901 unsafe { sys::napi_get_reference_value(env, val.inner, &mut result) },
902 "Failed to get reference value"
903 )?;
904 check_status!(
905 unsafe { sys::napi_delete_reference(env, val.inner) },
906 "delete Ref failed"
907 )?;
908 val.inner = ptr::null_mut();
909 drop(val);
910 Ok(result)
911 }
912}
913
914#[cfg(feature = "napi5")]
915pub struct FinalizeContext<T: 'static, Hint: 'static> {
916 pub env: Env,
917 pub value: T,
918 pub hint: Hint,
919}
920
921#[cfg(feature = "napi6")]
922pub enum KeyCollectionMode {
923 IncludePrototypes,
924 OwnOnly,
925}
926
927#[cfg(feature = "napi6")]
928impl TryFrom<sys::napi_key_collection_mode> for KeyCollectionMode {
929 type Error = Error;
930
931 fn try_from(value: sys::napi_key_collection_mode) -> Result<Self> {
932 match value {
933 sys::KeyCollectionMode::include_prototypes => Ok(Self::IncludePrototypes),
934 sys::KeyCollectionMode::own_only => Ok(Self::OwnOnly),
935 _ => Err(Error::new(
936 crate::Status::InvalidArg,
937 format!("Invalid key collection mode: {value}"),
938 )),
939 }
940 }
941}
942
943#[cfg(feature = "napi6")]
944impl From<KeyCollectionMode> for sys::napi_key_collection_mode {
945 fn from(value: KeyCollectionMode) -> Self {
946 match value {
947 KeyCollectionMode::IncludePrototypes => sys::KeyCollectionMode::include_prototypes,
948 KeyCollectionMode::OwnOnly => sys::KeyCollectionMode::own_only,
949 }
950 }
951}
952
953#[cfg(feature = "napi6")]
954pub enum KeyFilter {
955 AllProperties,
956 Writable,
957 Enumerable,
958 Configurable,
959 SkipStrings,
960 SkipSymbols,
961}
962
963#[cfg(feature = "napi6")]
964impl TryFrom<sys::napi_key_filter> for KeyFilter {
965 type Error = Error;
966
967 fn try_from(value: sys::napi_key_filter) -> Result<Self> {
968 match value {
969 sys::KeyFilter::all_properties => Ok(Self::AllProperties),
970 sys::KeyFilter::writable => Ok(Self::Writable),
971 sys::KeyFilter::enumerable => Ok(Self::Enumerable),
972 sys::KeyFilter::configurable => Ok(Self::Configurable),
973 sys::KeyFilter::skip_strings => Ok(Self::SkipStrings),
974 sys::KeyFilter::skip_symbols => Ok(Self::SkipSymbols),
975 _ => Err(Error::new(
976 crate::Status::InvalidArg,
977 format!("Invalid key filter [{value}]"),
978 )),
979 }
980 }
981}
982
983#[cfg(feature = "napi6")]
984impl From<KeyFilter> for sys::napi_key_filter {
985 fn from(value: KeyFilter) -> Self {
986 match value {
987 KeyFilter::AllProperties => sys::KeyFilter::all_properties,
988 KeyFilter::Writable => sys::KeyFilter::writable,
989 KeyFilter::Enumerable => sys::KeyFilter::enumerable,
990 KeyFilter::Configurable => sys::KeyFilter::configurable,
991 KeyFilter::SkipStrings => sys::KeyFilter::skip_strings,
992 KeyFilter::SkipSymbols => sys::KeyFilter::skip_symbols,
993 }
994 }
995}
996
997#[cfg(feature = "napi6")]
998pub enum KeyConversion {
999 KeepNumbers,
1000 NumbersToStrings,
1001}
1002
1003#[cfg(feature = "napi6")]
1004impl TryFrom<sys::napi_key_conversion> for KeyConversion {
1005 type Error = Error;
1006
1007 fn try_from(value: sys::napi_key_conversion) -> Result<Self> {
1008 match value {
1009 sys::KeyConversion::keep_numbers => Ok(Self::KeepNumbers),
1010 sys::KeyConversion::numbers_to_strings => Ok(Self::NumbersToStrings),
1011 _ => Err(Error::new(
1012 crate::Status::InvalidArg,
1013 format!("Invalid key conversion [{value}]"),
1014 )),
1015 }
1016 }
1017}
1018
1019#[cfg(feature = "napi6")]
1020impl From<KeyConversion> for sys::napi_key_conversion {
1021 fn from(value: KeyConversion) -> Self {
1022 match value {
1023 KeyConversion::KeepNumbers => sys::KeyConversion::keep_numbers,
1024 KeyConversion::NumbersToStrings => sys::KeyConversion::numbers_to_strings,
1025 }
1026 }
1027}
1028
1029#[cfg(feature = "napi5")]
1030unsafe extern "C" fn finalize_callback<T, Hint, F>(
1031 raw_env: sys::napi_env,
1032 finalize_data: *mut c_void,
1033 finalize_hint: *mut c_void,
1034) where
1035 T: 'static,
1036 Hint: 'static,
1037 F: FnOnce(FinalizeContext<T, Hint>),
1038{
1039 use crate::Env;
1040
1041 let (value, callback, raw_ref) =
1042 unsafe { *Box::from_raw(finalize_data as *mut (T, F, sys::napi_ref)) };
1043 let hint = unsafe { *Box::from_raw(finalize_hint as *mut Hint) };
1044 let env = Env::from_raw(raw_env);
1045 callback(FinalizeContext { env, value, hint });
1046 if !raw_ref.is_null() {
1047 check_status_or_throw!(
1048 raw_env,
1049 unsafe { sys::napi_delete_reference(raw_env, raw_ref) },
1050 "Delete reference in finalize callback failed"
1051 );
1052 }
1053}
1054
1055#[cfg(feature = "napi5")]
1056pub(crate) unsafe extern "C" fn finalize_closures(
1057 _env: sys::napi_env,
1058 data: *mut c_void,
1059 len: *mut c_void,
1060) {
1061 let (length, capacity): (usize, usize) = *unsafe { Box::from_raw(len.cast()) };
1062 let closures: Vec<*mut PropertyClosures> =
1063 unsafe { Vec::from_raw_parts(data.cast(), length, capacity) };
1064 for closure_ptr in closures.into_iter() {
1065 if !closure_ptr.is_null() {
1066 let closures = unsafe { Box::from_raw(closure_ptr) };
1067 if !closures.getter_closure.is_null() {
1069 if let Some(drop_fn) = closures.getter_drop_fn {
1070 unsafe { drop_fn(closures.getter_closure) };
1071 }
1072 }
1073 if !closures.setter_closure.is_null() {
1074 if let Some(drop_fn) = closures.setter_drop_fn {
1075 unsafe { drop_fn(closures.setter_closure) };
1076 }
1077 }
1078 }
1079 }
1080}