1use crate::{bindgen_prelude::*, check_status, sys, type_of, JsObject, ValueType};
2use std::{ffi::CString, ptr};
3
4pub type Object = JsObject;
5
6impl Object {
7 #[cfg(feature = "serde-json")]
8 pub(crate) fn new(env: sys::napi_env) -> Result<Self> {
9 let mut ptr = ptr::null_mut();
10 unsafe {
11 check_status!(
12 sys::napi_create_object(env, &mut ptr),
13 "Failed to create napi Object"
14 )?;
15 }
16
17 Ok(Self(crate::Value {
18 env,
19 value: ptr,
20 value_type: ValueType::Object,
21 }))
22 }
23
24 pub fn get<K: AsRef<str>, V: FromNapiValue>(&self, field: K) -> Result<Option<V>> {
25 unsafe {
26 self
27 .get_inner(field.as_ref())?
28 .map(|v| V::from_napi_value(self.0.env, v))
29 .transpose()
30 }
31 }
32
33 fn get_inner(&self, field: &str) -> Result<Option<sys::napi_value>> {
34 let c_field = CString::new(field)?;
35
36 unsafe {
37 let mut ret = ptr::null_mut();
38
39 check_status!(
40 sys::napi_get_named_property(self.0.env, self.0.value, c_field.as_ptr(), &mut ret),
41 "Failed to get property with field `{field}`",
42 )?;
43
44 let ty = type_of!(self.0.env, ret)?;
45
46 Ok(if ty == ValueType::Undefined {
47 None
48 } else {
49 Some(ret)
50 })
51 }
52 }
53
54 pub fn set<K: AsRef<str>, V: ToNapiValue>(&mut self, field: K, val: V) -> Result<()> {
55 unsafe { self.set_inner(field.as_ref(), V::to_napi_value(self.0.env, val)?) }
56 }
57
58 unsafe fn set_inner(&mut self, field: &str, napi_val: sys::napi_value) -> Result<()> {
59 let c_field = CString::new(field)?;
60
61 unsafe {
62 check_status!(
63 sys::napi_set_named_property(self.0.env, self.0.value, c_field.as_ptr(), napi_val),
64 "Failed to set property with field `{field}`",
65 )?;
66 Ok(())
67 }
68 }
69
70 pub fn keys(obj: &Object) -> Result<Vec<String>> {
71 let mut names = ptr::null_mut();
72 unsafe {
73 check_status!(
74 sys::napi_get_property_names(obj.0.env, obj.0.value, &mut names),
75 "Failed to get property names of given object"
76 )?;
77 }
78
79 let names = unsafe { Array::from_napi_value(obj.0.env, names)? };
80 let mut ret = vec![];
81
82 for i in 0..names.len() {
83 ret.push(names.get::<String>(i)?.unwrap());
84 }
85
86 Ok(ret)
87 }
88}
89
90impl TypeName for Object {
91 fn type_name() -> &'static str {
92 "Object"
93 }
94
95 fn value_type() -> ValueType {
96 ValueType::Object
97 }
98}
99
100impl ValidateNapiValue for JsObject {}
101