napi/bindgen_runtime/js_values/
class.rs1use std::any::type_name;
2use std::ffi::CString;
3use std::marker::PhantomData;
4use std::ops::{Deref, DerefMut};
5use std::ptr;
6
7use crate::{
8 bindgen_runtime::{
9 raw_finalize_unchecked, FromNapiValue, JsObjectValue, Object, ObjectFinalize, Reference,
10 Result, TypeName, ValidateNapiValue,
11 },
12 check_status, sys, Env, JsValue, Property, PropertyAttributes, Value, ValueType,
13};
14
15#[derive(Clone, Copy)]
16pub struct This<'env, T = Object<'env>> {
17 pub object: T,
18 _phantom: &'env PhantomData<()>,
19}
20
21impl<T> From<T> for This<'_, T> {
22 fn from(value: T) -> Self {
23 Self {
24 object: value,
25 _phantom: &PhantomData,
26 }
27 }
28}
29
30impl<T> Deref for This<'_, T> {
31 type Target = T;
32
33 fn deref(&self) -> &Self::Target {
34 &self.object
35 }
36}
37
38impl<T> DerefMut for This<'_, T> {
39 fn deref_mut(&mut self) -> &mut Self::Target {
40 &mut self.object
41 }
42}
43
44impl<'env, T: JsValue<'env>> JsValue<'env> for This<'_, T> {
45 fn value(&self) -> Value {
46 self.object.value()
47 }
48}
49
50impl<T: FromNapiValue> FromNapiValue for This<'_, T> {
51 unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
52 Ok(Self {
53 object: T::from_napi_value(env, napi_val)?,
54 _phantom: &PhantomData,
55 })
56 }
57}
58
59#[derive(Clone, Copy)]
60pub struct ClassInstance<'env, T: 'env> {
61 pub value: sys::napi_value,
62 env: sys::napi_env,
63 inner: *mut T,
64 _phantom: &'env PhantomData<()>,
65}
66
67impl<'env, T: 'env> JsValue<'env> for ClassInstance<'env, T> {
68 fn value(&self) -> Value {
69 Value {
70 env: self.env,
71 value: self.value,
72 value_type: ValueType::Object,
73 }
74 }
75}
76
77impl<'env, T: 'env> JsObjectValue<'env> for ClassInstance<'env, T> {}
78
79impl<'env, T: 'env> ClassInstance<'env, T> {
80 #[doc(hidden)]
81 pub unsafe fn new(value: sys::napi_value, env: sys::napi_env, inner: *mut T) -> Self {
82 Self {
83 value,
84 env,
85 inner: unsafe { &mut *inner },
86 _phantom: &PhantomData,
87 }
88 }
89
90 pub fn as_object<'a>(&self, env: &'a Env) -> Object<'a> {
91 Object(
92 Value {
93 env: env.raw(),
94 value: self.value,
95 value_type: ValueType::Object,
96 },
97 PhantomData,
98 )
99 }
100
101 pub fn assign_to_this<'a, 'this, U>(
105 &'a self,
106 name: &'a str,
107 this: &'a mut This<U>,
108 ) -> Result<ClassInstance<'this, T>>
109 where
110 'this: 'env,
111 U: FromNapiValue + JsValue<'this>,
112 {
113 let name = CString::new(name)?;
114 check_status!(
115 unsafe {
116 sys::napi_set_named_property(self.env, this.object.raw(), name.as_ptr(), self.value)
117 },
118 "Failed to assign ClassInstance<{}> to this",
119 std::any::type_name::<T>()
120 )?;
121 let val: ClassInstance<'this, T> = ClassInstance {
122 value: self.value,
123 env: self.env,
124 inner: self.inner,
125 _phantom: &PhantomData,
126 };
127 Ok(val)
128 }
129
130 pub fn assign_to_this_with_attributes<'a, 'this, U>(
134 &'a self,
135 name: &'a str,
136 attributes: PropertyAttributes,
137 this: &'a mut This<U>,
138 ) -> Result<ClassInstance<'this, T>>
139 where
140 'this: 'env,
141 U: FromNapiValue + JsValue<'this>,
142 {
143 let property = Property::new()
144 .with_utf8_name(name)?
145 .with_value(self)
146 .with_property_attributes(attributes);
147
148 check_status!(
149 unsafe {
150 sys::napi_define_properties(
151 self.env,
152 this.object.value().value,
153 1,
154 [property.raw()].as_ptr(),
155 )
156 },
157 "Failed to define properties on This in `assign_to_this_with_attributes`"
158 )?;
159
160 let val: ClassInstance<'this, T> = ClassInstance {
161 value: self.value,
162 env: self.env,
163 inner: self.inner,
164 _phantom: &PhantomData,
165 };
166 Ok(val)
167 }
168}
169
170impl<'env, T: 'env> TypeName for ClassInstance<'env, T>
171where
172 &'env T: TypeName,
173{
174 fn type_name() -> &'static str {
175 type_name::<&T>()
176 }
177
178 fn value_type() -> ValueType {
179 <&T>::value_type()
180 }
181}
182
183impl<'env, T: 'env> ValidateNapiValue for ClassInstance<'env, T>
184where
185 &'env T: ValidateNapiValue,
186{
187 unsafe fn validate(
188 env: sys::napi_env,
189 napi_val: sys::napi_value,
190 ) -> crate::Result<sys::napi_value> {
191 unsafe { <&'env T>::validate(env, napi_val) }
192 }
193}
194
195impl<'env, T: 'env> FromNapiValue for ClassInstance<'env, T> {
196 unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> crate::Result<Self> {
197 let mut value = ptr::null_mut();
198 check_status!(
199 unsafe { sys::napi_unwrap(env, napi_val, &mut value) },
200 "Unwrap value [{}] from class failed",
201 type_name::<T>(),
202 )?;
203 let value = unsafe { Box::from_raw(value as *mut T) };
204 Ok(Self {
205 value: napi_val,
206 inner: Box::leak(value),
207 env,
208 _phantom: &PhantomData,
209 })
210 }
211}
212
213impl<'env, T: 'env> Deref for ClassInstance<'env, T> {
214 type Target = T;
215
216 fn deref(&self) -> &Self::Target {
217 unsafe { &*self.inner }
218 }
219}
220
221impl<'env, T: 'env> DerefMut for ClassInstance<'env, T> {
222 fn deref_mut(&mut self) -> &mut Self::Target {
223 unsafe { &mut *self.inner }
224 }
225}
226
227impl<'env, T: 'env> AsRef<T> for ClassInstance<'env, T> {
228 fn as_ref(&self) -> &T {
229 unsafe { &*self.inner }
230 }
231}
232
233pub trait JavaScriptClassExt: Sized {
234 fn into_instance(self, env: &Env) -> Result<ClassInstance<'_, Self>>;
235 fn into_reference(self, env: Env) -> Result<Reference<Self>>;
236 fn instance_of<'env, V: JsValue<'env>>(env: &Env, value: &V) -> Result<bool>;
237}
238
239#[doc(hidden)]
243pub unsafe fn new_instance<T: 'static + ObjectFinalize>(
244 env: sys::napi_env,
245 wrapped_value: *mut std::ffi::c_void,
246 ctor_ref: sys::napi_ref,
247) -> Result<sys::napi_value> {
248 let mut ctor = std::ptr::null_mut();
249 check_status!(
250 sys::napi_get_reference_value(env, ctor_ref, &mut ctor),
251 "Failed to get constructor reference of class `{}`",
252 type_name::<T>(),
253 )?;
254
255 let mut result = std::ptr::null_mut();
256 crate::__private::___CALL_FROM_FACTORY.with(|inner| inner.set(true));
257 check_status!(
258 sys::napi_new_instance(env, ctor, 0, std::ptr::null_mut(), &mut result),
259 "Failed to construct class `{}`",
260 type_name::<T>(),
261 )?;
262 crate::__private::___CALL_FROM_FACTORY.with(|inner| inner.set(false));
263 let mut object_ref = std::ptr::null_mut();
264 let initial_finalize: Box<dyn FnOnce()> = Box::new(|| {});
265 let finalize_callbacks_ptr = std::rc::Rc::into_raw(std::rc::Rc::new(std::cell::Cell::new(
266 Box::into_raw(initial_finalize),
267 )));
268 check_status!(
269 sys::napi_wrap(
270 env,
271 result,
272 wrapped_value,
273 Some(raw_finalize_unchecked::<T>),
274 std::ptr::null_mut(),
275 &mut object_ref,
276 ),
277 "Failed to wrap native object of class `{}`",
278 type_name::<T>(),
279 )?;
280 Reference::<T>::add_ref(
281 env,
282 wrapped_value,
283 (wrapped_value, object_ref, finalize_callbacks_ptr),
284 );
285 Ok(result)
286}