1use std::any::{type_name, TypeId};
2#[cfg(feature = "napi6")]
3use std::convert::TryFrom;
4use std::ffi::{c_char, 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 property_descriptors = properties
467 .iter()
468 .map(|property| property.raw())
469 .collect::<Vec<sys::napi_property_descriptor>>();
470 let env = self.value().env;
471 #[cfg(feature = "napi5")]
472 {
473 if !properties.is_empty() {
474 let mut closures = properties
475 .iter()
476 .zip(property_descriptors.iter())
477 .filter(|(property, _)| property.has_closure_data())
478 .map(|(_, descriptor)| descriptor.data)
479 .filter(|data| !data.is_null())
480 .collect::<Vec<*mut std::ffi::c_void>>();
481 if !closures.is_empty() {
482 let finalize_hint = Box::into_raw(Box::new((closures.len(), closures.capacity())));
483 check_status!(
484 unsafe {
485 sys::napi_add_finalizer(
486 env,
487 self.value().value,
488 closures.as_mut_ptr().cast(),
489 Some(finalize_closures),
490 finalize_hint.cast(),
491 ptr::null_mut(),
492 )
493 },
494 "Failed to add finalizer"
495 )?;
496 std::mem::forget(closures);
497 }
498 }
499 }
500 check_status!(unsafe {
501 sys::napi_define_properties(
502 env,
503 self.value().value,
504 properties.len(),
505 property_descriptors.as_ptr(),
506 )
507 })
508 }
509
510 fn get_array_length(&self) -> Result<u32> {
514 if !(self.is_array()?) {
515 return Err(Error::new(
516 Status::ArrayExpected,
517 "Object is not array".to_owned(),
518 ));
519 }
520 self.get_array_length_unchecked()
521 }
522
523 fn get_array_length_unchecked(&self) -> Result<u32> {
525 let mut length: u32 = 0;
526 let env = self.value().env;
527 check_status!(unsafe { sys::napi_get_array_length(env, self.value().value, &mut length) })?;
528 Ok(length)
529 }
530
531 fn wrap<T: 'static>(&mut self, native_object: T, size_hint: Option<usize>) -> Result<()> {
534 let env = self.value().env;
535 let value = self.raw();
536 check_status!(unsafe {
537 sys::napi_wrap(
538 env,
539 value,
540 Box::into_raw(Box::new(TaggedObject::new(native_object))).cast(),
541 Some(raw_finalize::<TaggedObject<T>>),
542 Box::into_raw(Box::new(size_hint.unwrap_or(0) as i64)).cast(),
543 ptr::null_mut(),
544 )
545 })
546 }
547
548 #[allow(clippy::mut_from_ref)]
552 fn unwrap<T: 'static>(&self) -> Result<&mut T> {
553 let env = self.value().env;
554 let value = self.raw();
555 unsafe {
556 let mut unknown_tagged_object: *mut c_void = ptr::null_mut();
557 check_status!(
558 sys::napi_unwrap(env, value, &mut unknown_tagged_object),
559 "Failed to unwrap value of the Object"
560 )?;
561
562 let type_id = unknown_tagged_object as *const TypeId;
563 if *type_id == TypeId::of::<T>() {
564 let tagged_object = unknown_tagged_object as *mut TaggedObject<T>;
565 (*tagged_object).object.as_mut().ok_or_else(|| {
566 Error::new(
567 Status::InvalidArg,
568 "Invalid argument, nothing attach to js_object".to_owned(),
569 )
570 })
571 } else {
572 Err(Error::new(
573 Status::InvalidArg,
574 format!(
575 "Invalid argument, {} on unwrap is not the type of wrapped object",
576 type_name::<T>()
577 ),
578 ))
579 }
580 }
581 }
582
583 fn remove_wrapped<T: 'static>(&mut self) -> Result<()> {
587 let env = self.value().env;
588 let value = self.raw();
589 unsafe {
590 let mut unknown_tagged_object = ptr::null_mut();
591 check_status!(sys::napi_remove_wrap(
592 env,
593 value,
594 &mut unknown_tagged_object,
595 ))?;
596 let type_id = unknown_tagged_object as *const TypeId;
597 if *type_id == TypeId::of::<T>() {
598 drop(Box::from_raw(unknown_tagged_object as *mut TaggedObject<T>));
599 Ok(())
600 } else {
601 Err(Error::new(
602 Status::InvalidArg,
603 format!(
604 "Invalid argument, {} on unwrap is not the type of wrapped object",
605 type_name::<T>()
606 ),
607 ))
608 }
609 }
610 }
611
612 #[cfg(feature = "napi5")]
613 fn add_finalizer<T, Hint, F>(
617 &mut self,
618 native: T,
619 finalize_hint: Hint,
620 finalize_cb: F,
621 ) -> Result<()>
622 where
623 T: 'static,
624 Hint: 'static,
625 F: FnOnce(FinalizeContext<T, Hint>) + 'static,
626 {
627 let mut maybe_ref = ptr::null_mut();
628 let env = self.value().env;
629 let value = self.raw();
630 let wrap_context = Box::leak(Box::new((native, finalize_cb, ptr::null_mut())));
631 check_status!(unsafe {
632 sys::napi_add_finalizer(
633 env,
634 value,
635 (wrap_context as *mut (T, F, sys::napi_ref)).cast(),
636 Some(finalize_callback::<T, Hint, F>),
637 Box::into_raw(Box::new(finalize_hint)).cast(),
638 &mut maybe_ref, )
640 })?;
641 wrap_context.2 = maybe_ref;
642 Ok(())
643 }
644
645 #[cfg(feature = "napi8")]
646 fn freeze(&mut self) -> Result<()> {
650 let env = self.value().env;
651 check_status!(unsafe { sys::napi_object_freeze(env, self.value().value) })
652 }
653
654 #[cfg(feature = "napi8")]
655 fn seal(&mut self) -> Result<()> {
658 let env = self.value().env;
659 check_status!(unsafe { sys::napi_object_seal(env, self.value().value) })
660 }
661}
662
663#[derive(Clone, Copy)]
664pub struct Object<'env>(pub(crate) Value, pub(crate) PhantomData<&'env ()>);
665
666impl<'env> JsValue<'env> for Object<'env> {
667 fn value(&self) -> Value {
668 self.0
669 }
670}
671
672impl<'env> JsObjectValue<'env> for Object<'env> {}
673
674impl TypeName for Object<'_> {
675 fn type_name() -> &'static str {
676 "Object"
677 }
678
679 fn value_type() -> ValueType {
680 ValueType::Object
681 }
682}
683
684impl ValidateNapiValue for Object<'_> {}
685
686impl FromNapiValue for Object<'_> {
687 unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
688 Ok(Self(
689 Value {
690 env,
691 value: napi_val,
692 value_type: ValueType::Object,
693 },
694 PhantomData,
695 ))
696 }
697}
698
699impl ToNapiValue for &Object<'_> {
700 unsafe fn to_napi_value(_env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
701 Ok(val.0.value)
702 }
703}
704
705#[doc(hidden)]
710pub unsafe fn get_named_property_raw(
711 env: sys::napi_env,
712 obj: sys::napi_value,
713 field: *const c_char,
714) -> Result<Option<sys::napi_value>> {
715 let mut ret = ptr::null_mut();
716
717 check_status!(
718 unsafe { sys::napi_get_named_property(env, obj, field, &mut ret) },
719 "Failed to get property",
720 )?;
721
722 let ty = type_of!(env, ret)?;
723
724 Ok(if ty == ValueType::Undefined {
725 None
726 } else {
727 Some(ret)
728 })
729}
730
731#[doc(hidden)]
736pub unsafe fn set_named_property_raw(
737 env: sys::napi_env,
738 obj: sys::napi_value,
739 field: *const c_char,
740 value: sys::napi_value,
741) -> Result<()> {
742 check_status!(
743 unsafe { sys::napi_set_named_property(env, obj, field, value) },
744 "Failed to set property"
745 )
746}
747
748#[doc(hidden)]
749#[inline]
750pub unsafe fn from_raw_required_field<T>(
751 env: sys::napi_env,
752 raw: Option<sys::napi_value>,
753 struct_name: &str,
754 field: &str,
755) -> Result<T>
756where
757 T: FromNapiValue,
758{
759 let Some(raw) = raw else {
760 return Err(crate::missing_field_error(field));
761 };
762
763 unsafe { T::from_napi_value(env, raw) }.map_err(|err| {
764 if struct_name.is_empty() {
765 err
766 } else {
767 crate::decorate_field_error(err, struct_name, field)
768 }
769 })
770}
771
772#[doc(hidden)]
773#[inline]
774pub unsafe fn from_raw_optional_field<T>(
775 env: sys::napi_env,
776 raw: Option<sys::napi_value>,
777 struct_name: &str,
778 field: &str,
779) -> Result<Option<T>>
780where
781 T: FromNapiValue,
782{
783 match raw {
784 Some(raw) => unsafe { T::from_napi_value(env, raw) }
785 .map(Some)
786 .map_err(|err| {
787 if struct_name.is_empty() {
788 err
789 } else {
790 crate::decorate_field_error(err, struct_name, field)
791 }
792 }),
793 None => Ok(None),
794 }
795}
796
797impl Object<'_> {
798 pub fn from_raw(env: sys::napi_env, value: sys::napi_value) -> Self {
800 Self(
801 Value {
802 env,
803 value,
804 value_type: ValueType::Object,
805 },
806 PhantomData,
807 )
808 }
809
810 pub fn new(env: &Env) -> Result<Self> {
812 let mut ptr = ptr::null_mut();
813 unsafe {
814 check_status!(
815 sys::napi_create_object(env.0, &mut ptr),
816 "Failed to create napi Object"
817 )?;
818 }
819
820 Ok(Self(
821 crate::Value {
822 env: env.0,
823 value: ptr,
824 value_type: ValueType::Object,
825 },
826 PhantomData,
827 ))
828 }
829
830 pub fn get<V: FromNapiValue>(&self, field: &str) -> Result<Option<V>> {
832 unsafe {
833 self
834 .get_inner(field)?
835 .map(|v| V::from_napi_value(self.0.env, v))
836 .transpose()
837 }
838 }
839
840 fn get_inner(&self, field: &str) -> Result<Option<sys::napi_value>> {
841 unsafe {
842 let mut property_key = std::ptr::null_mut();
843 check_status!(
844 sys::napi_create_string_utf8(
845 self.0.env,
846 field.as_ptr().cast(),
847 field.len() as isize,
848 &mut property_key,
849 ),
850 "Failed to create property key with `{field}`"
851 )?;
852
853 let mut ret = ptr::null_mut();
854
855 check_status!(
856 sys::napi_get_property(self.0.env, self.0.value, property_key, &mut ret),
857 "Failed to get property with field `{field}`",
858 )?;
859
860 let ty = type_of!(self.0.env, ret)?;
861
862 Ok(if ty == ValueType::Undefined {
863 None
864 } else {
865 Some(ret)
866 })
867 }
868 }
869
870 pub fn set<K: AsRef<str>, V: ToNapiValue>(&mut self, field: K, val: V) -> Result<()> {
872 unsafe { self.set_inner(field.as_ref(), V::to_napi_value(self.0.env, val)?) }
873 }
874
875 unsafe fn set_inner(&mut self, field: &str, napi_val: sys::napi_value) -> Result<()> {
876 let mut property_key = std::ptr::null_mut();
877 check_status!(
878 unsafe {
879 sys::napi_create_string_utf8(
880 self.0.env,
881 field.as_ptr().cast(),
882 field.len() as isize,
883 &mut property_key,
884 )
885 },
886 "Failed to create property key with `{field}`"
887 )?;
888
889 check_status!(
890 unsafe { sys::napi_set_property(self.0.env, self.0.value, property_key, napi_val) },
891 "Failed to set property with field `{field}`"
892 )?;
893 Ok(())
894 }
895
896 pub fn keys(obj: &Object) -> Result<Vec<String>> {
898 let mut names = ptr::null_mut();
899 unsafe {
900 check_status!(
901 sys::napi_get_property_names(obj.0.env, obj.0.value, &mut names),
902 "Failed to get property names of given object"
903 )?;
904 }
905
906 let names = unsafe { Array::from_napi_value(obj.0.env, names)? };
907 let mut ret = vec![];
908
909 for i in 0..names.len() {
910 ret.push(names.get_element::<String>(i)?);
911 }
912
913 Ok(ret)
914 }
915
916 pub fn create_ref<const LEAK_CHECK: bool>(&self) -> Result<ObjectRef<LEAK_CHECK>> {
920 let mut ref_ = ptr::null_mut();
921 check_status!(
922 unsafe { sys::napi_create_reference(self.0.env, self.0.value, 1, &mut ref_) },
923 "Failed to create reference"
924 )?;
925 Ok(ObjectRef { inner: ref_ })
926 }
927}
928
929pub struct ObjectRef<const LEAK_CHECK: bool = true> {
935 pub(crate) inner: sys::napi_ref,
936}
937
938unsafe impl<const LEAK_CHECK: bool> Send for ObjectRef<LEAK_CHECK> {}
939
940impl<const LEAK_CHECK: bool> Drop for ObjectRef<LEAK_CHECK> {
941 fn drop(&mut self) {
942 if LEAK_CHECK && !self.inner.is_null() {
943 eprintln!("ObjectRef is not unref, it considered as a memory leak");
944 }
945 }
946}
947
948impl<const LEAK_CHECK: bool> ObjectRef<LEAK_CHECK> {
949 pub fn get_value<'env>(&self, env: &'env Env) -> Result<Object<'env>> {
951 let mut result = ptr::null_mut();
952 check_status!(
953 unsafe { sys::napi_get_reference_value(env.0, self.inner, &mut result) },
954 "Failed to get reference value"
955 )?;
956 Ok(Object::from_raw(env.0, result))
957 }
958
959 pub fn unref(mut self, env: &Env) -> Result<()> {
961 check_status!(
962 unsafe { sys::napi_delete_reference(env.0, self.inner) },
963 "delete Ref failed"
964 )?;
965 self.inner = ptr::null_mut();
966 Ok(())
967 }
968}
969
970impl<const LEAK_CHECK: bool> FromNapiValue for ObjectRef<LEAK_CHECK> {
971 unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
972 let mut ref_ = ptr::null_mut();
973 check_status!(
974 unsafe { sys::napi_create_reference(env, napi_val, 1, &mut ref_) },
975 "Failed to create reference"
976 )?;
977 Ok(Self { inner: ref_ })
978 }
979}
980
981impl<const LEAK_CHECK: bool> ToNapiValue for &ObjectRef<LEAK_CHECK> {
982 unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
983 let mut result = ptr::null_mut();
984 check_status!(
985 unsafe { sys::napi_get_reference_value(env, val.inner, &mut result) },
986 "Failed to get reference value"
987 )?;
988 Ok(result)
989 }
990}
991
992impl<const LEAK_CHECK: bool> ToNapiValue for ObjectRef<LEAK_CHECK> {
993 unsafe fn to_napi_value(env: sys::napi_env, mut val: Self) -> Result<sys::napi_value> {
994 let mut result = ptr::null_mut();
995 check_status!(
996 unsafe { sys::napi_get_reference_value(env, val.inner, &mut result) },
997 "Failed to get reference value"
998 )?;
999 check_status!(
1000 unsafe { sys::napi_delete_reference(env, val.inner) },
1001 "delete Ref failed"
1002 )?;
1003 val.inner = ptr::null_mut();
1004 drop(val);
1005 Ok(result)
1006 }
1007}
1008
1009#[cfg(feature = "napi5")]
1010pub struct FinalizeContext<T: 'static, Hint: 'static> {
1011 pub env: Env,
1012 pub value: T,
1013 pub hint: Hint,
1014}
1015
1016#[cfg(feature = "napi6")]
1017pub enum KeyCollectionMode {
1018 IncludePrototypes,
1019 OwnOnly,
1020}
1021
1022#[cfg(feature = "napi6")]
1023impl TryFrom<sys::napi_key_collection_mode> for KeyCollectionMode {
1024 type Error = Error;
1025
1026 fn try_from(value: sys::napi_key_collection_mode) -> Result<Self> {
1027 match value {
1028 sys::KeyCollectionMode::include_prototypes => Ok(Self::IncludePrototypes),
1029 sys::KeyCollectionMode::own_only => Ok(Self::OwnOnly),
1030 _ => Err(Error::new(
1031 crate::Status::InvalidArg,
1032 format!("Invalid key collection mode: {value}"),
1033 )),
1034 }
1035 }
1036}
1037
1038#[cfg(feature = "napi6")]
1039impl From<KeyCollectionMode> for sys::napi_key_collection_mode {
1040 fn from(value: KeyCollectionMode) -> Self {
1041 match value {
1042 KeyCollectionMode::IncludePrototypes => sys::KeyCollectionMode::include_prototypes,
1043 KeyCollectionMode::OwnOnly => sys::KeyCollectionMode::own_only,
1044 }
1045 }
1046}
1047
1048#[cfg(feature = "napi6")]
1049pub enum KeyFilter {
1050 AllProperties,
1051 Writable,
1052 Enumerable,
1053 Configurable,
1054 SkipStrings,
1055 SkipSymbols,
1056}
1057
1058#[cfg(feature = "napi6")]
1059impl TryFrom<sys::napi_key_filter> for KeyFilter {
1060 type Error = Error;
1061
1062 fn try_from(value: sys::napi_key_filter) -> Result<Self> {
1063 match value {
1064 sys::KeyFilter::all_properties => Ok(Self::AllProperties),
1065 sys::KeyFilter::writable => Ok(Self::Writable),
1066 sys::KeyFilter::enumerable => Ok(Self::Enumerable),
1067 sys::KeyFilter::configurable => Ok(Self::Configurable),
1068 sys::KeyFilter::skip_strings => Ok(Self::SkipStrings),
1069 sys::KeyFilter::skip_symbols => Ok(Self::SkipSymbols),
1070 _ => Err(Error::new(
1071 crate::Status::InvalidArg,
1072 format!("Invalid key filter [{value}]"),
1073 )),
1074 }
1075 }
1076}
1077
1078#[cfg(feature = "napi6")]
1079impl From<KeyFilter> for sys::napi_key_filter {
1080 fn from(value: KeyFilter) -> Self {
1081 match value {
1082 KeyFilter::AllProperties => sys::KeyFilter::all_properties,
1083 KeyFilter::Writable => sys::KeyFilter::writable,
1084 KeyFilter::Enumerable => sys::KeyFilter::enumerable,
1085 KeyFilter::Configurable => sys::KeyFilter::configurable,
1086 KeyFilter::SkipStrings => sys::KeyFilter::skip_strings,
1087 KeyFilter::SkipSymbols => sys::KeyFilter::skip_symbols,
1088 }
1089 }
1090}
1091
1092#[cfg(feature = "napi6")]
1093pub enum KeyConversion {
1094 KeepNumbers,
1095 NumbersToStrings,
1096}
1097
1098#[cfg(feature = "napi6")]
1099impl TryFrom<sys::napi_key_conversion> for KeyConversion {
1100 type Error = Error;
1101
1102 fn try_from(value: sys::napi_key_conversion) -> Result<Self> {
1103 match value {
1104 sys::KeyConversion::keep_numbers => Ok(Self::KeepNumbers),
1105 sys::KeyConversion::numbers_to_strings => Ok(Self::NumbersToStrings),
1106 _ => Err(Error::new(
1107 crate::Status::InvalidArg,
1108 format!("Invalid key conversion [{value}]"),
1109 )),
1110 }
1111 }
1112}
1113
1114#[cfg(feature = "napi6")]
1115impl From<KeyConversion> for sys::napi_key_conversion {
1116 fn from(value: KeyConversion) -> Self {
1117 match value {
1118 KeyConversion::KeepNumbers => sys::KeyConversion::keep_numbers,
1119 KeyConversion::NumbersToStrings => sys::KeyConversion::numbers_to_strings,
1120 }
1121 }
1122}
1123
1124#[cfg(feature = "napi5")]
1125unsafe extern "C" fn finalize_callback<T, Hint, F>(
1126 raw_env: sys::napi_env,
1127 finalize_data: *mut c_void,
1128 finalize_hint: *mut c_void,
1129) where
1130 T: 'static,
1131 Hint: 'static,
1132 F: FnOnce(FinalizeContext<T, Hint>),
1133{
1134 use crate::Env;
1135
1136 let (value, callback, raw_ref) =
1137 unsafe { *Box::from_raw(finalize_data as *mut (T, F, sys::napi_ref)) };
1138 let hint = unsafe { *Box::from_raw(finalize_hint as *mut Hint) };
1139 let env = Env::from_raw(raw_env);
1140 callback(FinalizeContext { env, value, hint });
1141 if !raw_ref.is_null() {
1142 check_status_or_throw!(
1143 raw_env,
1144 unsafe { sys::napi_delete_reference(raw_env, raw_ref) },
1145 "Delete reference in finalize callback failed"
1146 );
1147 }
1148}
1149
1150#[cfg(feature = "napi5")]
1151pub(crate) unsafe extern "C" fn finalize_closures(
1152 _env: sys::napi_env,
1153 data: *mut c_void,
1154 len: *mut c_void,
1155) {
1156 let (length, capacity): (usize, usize) = *unsafe { Box::from_raw(len.cast()) };
1157 let closures: Vec<*mut PropertyClosures> =
1158 unsafe { Vec::from_raw_parts(data.cast(), length, capacity) };
1159 for closure_ptr in closures.into_iter() {
1160 if !closure_ptr.is_null() {
1161 let closures = unsafe { Box::from_raw(closure_ptr) };
1162 if !closures.getter_closure.is_null() {
1164 if let Some(drop_fn) = closures.getter_drop_fn {
1165 unsafe { drop_fn(closures.getter_closure) };
1166 }
1167 }
1168 if !closures.setter_closure.is_null() {
1169 if let Some(drop_fn) = closures.setter_drop_fn {
1170 unsafe { drop_fn(closures.setter_closure) };
1171 }
1172 }
1173 }
1174 }
1175}