1use 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::{
11 bindgen_runtime::{FromNapiValue, This, ToNapiValue},
12 Env,
13};
14use crate::{sys, Callback, NapiRaw, Result};
15
16#[cfg(feature = "napi5")]
17#[derive(Copy, Clone)]
18pub struct PropertyClosures {
19 pub setter_closure: *mut c_void,
20 pub getter_closure: *mut c_void,
21}
22
23#[cfg(feature = "napi5")]
24impl Default for PropertyClosures {
25 fn default() -> Self {
26 Self {
27 setter_closure: ptr::null_mut(),
28 getter_closure: ptr::null_mut(),
29 }
30 }
31}
32
33#[derive(Clone)]
34pub struct Property {
35 pub name: CString,
36 getter: sys::napi_callback,
37 setter: sys::napi_callback,
38 method: sys::napi_callback,
39 attrs: PropertyAttributes,
40 value: sys::napi_value,
41 pub(crate) is_ctor: bool,
42 #[cfg(feature = "napi5")]
43 pub(crate) closures: PropertyClosures,
44}
45
46impl Default for Property {
47 fn default() -> Self {
48 Property {
49 name: Default::default(),
50 getter: Default::default(),
51 setter: Default::default(),
52 method: Default::default(),
53 attrs: Default::default(),
54 value: ptr::null_mut(),
55 is_ctor: Default::default(),
56 #[cfg(feature = "napi5")]
57 closures: PropertyClosures::default(),
58 }
59 }
60}
61
62bitflags! {
63 #[derive(Debug, Copy, Clone)]
64 pub struct PropertyAttributes: i32 {
65 const Default = sys::PropertyAttributes::default;
66 const Writable = sys::PropertyAttributes::writable;
67 const Enumerable = sys::PropertyAttributes::enumerable;
68 const Configurable = sys::PropertyAttributes::configurable;
69 const Static = sys::PropertyAttributes::static_;
70 }
71}
72
73impl Default for PropertyAttributes {
74 fn default() -> Self {
75 PropertyAttributes::Configurable | PropertyAttributes::Enumerable | PropertyAttributes::Writable
76 }
77}
78
79impl From<PropertyAttributes> for sys::napi_property_attributes {
80 fn from(value: PropertyAttributes) -> Self {
81 value.bits()
82 }
83}
84
85impl Property {
86 pub fn new(name: &str) -> Result<Self> {
87 Ok(Property {
88 name: CString::new(name)?,
89 ..Default::default()
90 })
91 }
92
93 pub fn with_name(mut self, name: &str) -> Self {
94 self.name = CString::new(name).unwrap();
95 self
96 }
97
98 pub fn with_method(mut self, callback: Callback) -> Self {
99 self.method = Some(callback);
100 self
101 }
102
103 pub fn with_getter(mut self, callback: Callback) -> Self {
104 self.getter = Some(callback);
105 self
106 }
107
108 #[cfg(feature = "napi5")]
109 pub fn with_getter_closure<R, F>(mut self, callback: F) -> Self
110 where
111 F: 'static + Fn(Env, This) -> Result<R>,
112 R: ToNapiValue,
113 {
114 let boxed_callback = Box::new(callback);
115 let closure_data_ptr: *mut F = Box::into_raw(boxed_callback);
116 self.closures.getter_closure = closure_data_ptr.cast();
117
118 let (*mut napi_env__, *mut napi_callback_info__) -> *mut napi_value__" title="fun">fun = crate::trampoline_getter::<R, F>;
119 self.getter = Some(fun);
120 self
121 }
122
123 pub fn with_setter(mut self, callback: Callback) -> Self {
124 self.setter = Some(callback);
125 self
126 }
127
128 #[cfg(feature = "napi5")]
129 pub fn with_setter_closure<F, V>(mut self, callback: F) -> Self
130 where
131 F: 'static + Fn(crate::Env, This, V) -> Result<()>,
132 V: FromNapiValue,
133 {
134 let boxed_callback = Box::new(callback);
135 let closure_data_ptr: *mut F = Box::into_raw(boxed_callback);
136 self.closures.setter_closure = closure_data_ptr.cast();
137
138 let (*mut napi_env__, *mut napi_callback_info__) -> *mut napi_value__" title="fun">fun = crate::trampoline_setter::<V, F>;
139 self.setter = Some(fun);
140 self
141 }
142
143 pub fn with_property_attributes(mut self, attributes: PropertyAttributes) -> Self {
144 self.attrs = attributes;
145 self
146 }
147
148 pub fn with_value<T: NapiRaw>(mut self, value: &T) -> Self {
149 self.value = unsafe { T::raw(value) };
150 self
151 }
152
153 pub(crate) fn raw(&self) -> sys::napi_property_descriptor {
154 #[cfg(feature = "napi5")]
155 let closures = Box::into_raw(Box::new(self.closures));
156 sys::napi_property_descriptor {
157 utf8name: self.name.as_ptr(),
158 name: ptr::null_mut(),
159 method: self.method,
160 getter: self.getter,
161 setter: self.setter,
162 value: self.value,
163 attributes: self.attrs.into(),
164 #[cfg(not(feature = "napi5"))]
165 data: ptr::null_mut(),
166 #[cfg(feature = "napi5")]
167 data: closures.cast(),
168 }
169 }
170
171 pub fn with_ctor(mut self, callback: Callback) -> Self {
172 self.method = Some(callback);
173 self.is_ctor = true;
174 self
175 }
176}
177