napi/js_values/
object_property.rs1use std::convert::From;
2#[cfg(feature = "napi5")]
3use std::ffi::c_void;
4use std::ffi::CString;
5use std::ptr;
6
7use bitflags::bitflags;
8
9#[cfg(feature = "napi5")]
10use crate::bindgen_runtime::{FromNapiValue, This};
11use crate::{bindgen_runtime::ToNapiValue, sys, Callback, Env, JsValue, Result};
12
13#[cfg(feature = "napi5")]
14#[derive(Copy, Clone)]
15pub struct PropertyClosures {
16 pub setter_closure: *mut c_void,
17 pub getter_closure: *mut c_void,
18 pub setter_drop_fn: Option<unsafe fn(*mut c_void)>,
19 pub getter_drop_fn: Option<unsafe fn(*mut c_void)>,
20}
21
22#[cfg(feature = "napi5")]
23impl Default for PropertyClosures {
24 fn default() -> Self {
25 Self {
26 setter_closure: ptr::null_mut(),
27 getter_closure: ptr::null_mut(),
28 setter_drop_fn: None,
29 getter_drop_fn: None,
30 }
31 }
32}
33
34#[derive(Clone)]
35pub struct Property {
36 utf8_name: Option<CString>,
37 name: sys::napi_value,
38 getter: sys::napi_callback,
39 setter: sys::napi_callback,
40 method: sys::napi_callback,
41 attrs: PropertyAttributes,
42 value: sys::napi_value,
43 pub(crate) is_ctor: bool,
44 #[cfg(feature = "napi5")]
45 pub(crate) closures: PropertyClosures,
46}
47
48impl Default for Property {
49 fn default() -> Self {
50 Property {
51 utf8_name: Default::default(),
52 name: ptr::null_mut(),
53 getter: Default::default(),
54 setter: Default::default(),
55 method: Default::default(),
56 attrs: Default::default(),
57 value: ptr::null_mut(),
58 is_ctor: Default::default(),
59 #[cfg(feature = "napi5")]
60 closures: PropertyClosures::default(),
61 }
62 }
63}
64
65bitflags! {
66 #[derive(Debug, Copy, Clone)]
67 pub struct PropertyAttributes: i32 {
68 const Default = sys::PropertyAttributes::default;
69 const Writable = sys::PropertyAttributes::writable;
70 const Enumerable = sys::PropertyAttributes::enumerable;
71 const Configurable = sys::PropertyAttributes::configurable;
72 const Static = sys::PropertyAttributes::static_;
73 }
74}
75
76impl Default for PropertyAttributes {
77 fn default() -> Self {
78 PropertyAttributes::Configurable | PropertyAttributes::Enumerable | PropertyAttributes::Writable
79 }
80}
81
82impl From<PropertyAttributes> for sys::napi_property_attributes {
83 fn from(value: PropertyAttributes) -> Self {
84 value.bits()
85 }
86}
87
88impl Property {
89 pub fn new() -> Self {
90 Default::default()
91 }
92
93 pub fn with_utf8_name(mut self, name: &str) -> Result<Self> {
94 self.utf8_name = Some(CString::new(name)?);
95 Ok(self)
96 }
97
98 pub fn with_name<T: ToNapiValue>(mut self, env: &Env, name: T) -> Result<Self> {
99 self.name = unsafe { T::to_napi_value(env.0, name)? };
100 Ok(self)
101 }
102
103 pub fn with_method(mut self, callback: Callback) -> Self {
104 self.method = Some(callback);
105 self
106 }
107
108 pub fn with_getter(mut self, callback: Callback) -> Self {
109 self.getter = Some(callback);
110 self
111 }
112
113 #[cfg(feature = "napi5")]
114 pub fn with_getter_closure<R, F>(mut self, callback: F) -> Self
115 where
116 F: 'static + Fn(Env, This) -> Result<R>,
117 R: ToNapiValue,
118 {
119 let boxed_callback = Box::new(callback);
120 let closure_data_ptr: *mut F = Box::into_raw(boxed_callback);
121 self.closures.getter_closure = closure_data_ptr.cast();
122 self.closures.getter_drop_fn = Some(|ptr: *mut c_void| unsafe {
123 drop(Box::from_raw(ptr as *mut F));
124 });
125
126 let fun = crate::trampoline_getter::<R, F>;
127 self.getter = Some(fun);
128 self
129 }
130
131 pub fn with_setter(mut self, callback: Callback) -> Self {
132 self.setter = Some(callback);
133 self
134 }
135
136 #[cfg(feature = "napi5")]
137 pub fn with_setter_closure<F, V>(mut self, callback: F) -> Self
138 where
139 F: 'static + Fn(crate::Env, This, V) -> Result<()>,
140 V: FromNapiValue,
141 {
142 let boxed_callback = Box::new(callback);
143 let closure_data_ptr: *mut F = Box::into_raw(boxed_callback);
144 self.closures.setter_closure = closure_data_ptr.cast();
145 self.closures.setter_drop_fn = Some(|ptr: *mut c_void| unsafe {
146 drop(Box::from_raw(ptr as *mut F));
147 });
148
149 let fun = crate::trampoline_setter::<V, F>;
150 self.setter = Some(fun);
151 self
152 }
153
154 pub fn with_property_attributes(mut self, attributes: PropertyAttributes) -> Self {
155 self.attrs = attributes;
156 self
157 }
158
159 pub fn with_value<'env, T: JsValue<'env>>(mut self, value: &T) -> Self {
160 self.value = T::raw(value);
161 self
162 }
163
164 pub fn with_napi_value<T: ToNapiValue>(mut self, env: &Env, value: T) -> Result<Self> {
165 self.value = unsafe { T::to_napi_value(env.0, value)? };
166 Ok(self)
167 }
168
169 pub(crate) fn raw(&self) -> sys::napi_property_descriptor {
170 #[cfg(feature = "napi5")]
171 let data = if self.closures.getter_closure.is_null() && self.closures.setter_closure.is_null() {
172 ptr::null_mut()
174 } else {
175 Box::into_raw(Box::new(self.closures)).cast()
177 };
178
179 sys::napi_property_descriptor {
180 utf8name: match self.utf8_name {
181 Some(ref name) => name.as_ptr(),
182 None => ptr::null(),
183 },
184 name: self.name,
185 method: self.method,
186 getter: self.getter,
187 setter: self.setter,
188 value: self.value,
189 attributes: self.attrs.into(),
190 #[cfg(not(feature = "napi5"))]
191 data: ptr::null_mut(),
192 #[cfg(feature = "napi5")]
193 data,
194 }
195 }
196
197 pub fn with_ctor(mut self, callback: Callback) -> Self {
198 self.method = Some(callback);
199 self.is_ctor = true;
200 self
201 }
202}