1use std::{
2 ptr,
3 rc::Rc,
4 sync::{Arc, Mutex},
5};
6
7use crate::{check_status, sys, Error, JsUnknown, NapiRaw, NapiValue, Result, Status, ValueType};
8
9mod array;
10mod arraybuffer;
11#[cfg(feature = "napi6")]
12mod bigint;
13mod boolean;
14mod buffer;
15mod class;
16#[cfg(all(feature = "chrono_date", feature = "napi5"))]
17mod date;
18mod either;
19mod external;
20mod function;
21mod map;
22mod nil;
23mod number;
24mod object;
25#[cfg(all(feature = "tokio_rt", feature = "napi4"))]
26mod promise;
27#[cfg(feature = "serde-json")]
28mod serde;
29mod string;
30mod symbol;
31mod task;
32mod value_ref;
33
34pub use crate::js_values::JsUnknown as Unknown;
35#[cfg(feature = "napi5")]
36pub use crate::JsDate as Date;
37pub use array::*;
38pub use arraybuffer::*;
39#[cfg(feature = "napi6")]
40pub use bigint::*;
41pub use buffer::*;
42pub use class::*;
43pub use either::*;
44pub use external::*;
45pub use function::*;
46pub use nil::*;
47pub use object::*;
48#[cfg(all(feature = "tokio_rt", feature = "napi4"))]
49pub use promise::*;
50pub use string::*;
51pub use symbol::*;
52pub use task::*;
53pub use value_ref::*;
54
55#[cfg(feature = "latin1")]
56pub use string::latin1_string::*;
57
58pub trait TypeName {
59 fn type_name() -> &'static str;
60
61 fn value_type() -> ValueType;
62}
63
64pub trait ToNapiValue {
65 /// # Safety
66 ///
67 /// this function called to convert rust values to napi values
68 unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value>;
69}
70
71impl TypeName for JsUnknown {
72 fn type_name() -> &'static str {
73 "unknown"
74 }
75
76 fn value_type() -> ValueType {
77 ValueType::Unknown
78 }
79}
80
81impl ValidateNapiValue for JsUnknown {}
82
83impl ToNapiValue for sys::napi_value {
84 unsafe fn to_napi_value(_env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
85 Ok(val)
86 }
87}
88
89impl<T: NapiRaw> ToNapiValue for T {
90 unsafe fn to_napi_value(_env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
91 Ok(unsafe { NapiRaw::raw(&val) })
92 }
93}
94
95impl<T: NapiValue> FromNapiValue for T {
96 unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
97 Ok(unsafe { T::from_raw_unchecked(env, value:napi_val) })
98 }
99}
100
101pub trait FromNapiValue: Sized {
102 /// # Safety
103 ///
104 /// this function called to convert napi values to native rust values
105 unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self>;
106
107 fn from_unknown(value: JsUnknown) -> Result<Self> {
108 unsafe { Self::from_napi_value(value.0.env, napi_val:value.0.value) }
109 }
110}
111
112pub trait FromNapiRef {
113 /// # Safety
114 ///
115 /// this function called to convert napi values to native rust values
116 unsafe fn from_napi_ref(env: sys::napi_env, napi_val: sys::napi_value) -> Result<&'static Self>;
117}
118
119pub trait FromNapiMutRef {
120 /// # Safety
121 ///
122 /// this function called to convert napi values to native rust values
123 unsafe fn from_napi_mut_ref(
124 env: sys::napi_env,
125 napi_val: sys::napi_value,
126 ) -> Result<&'static mut Self>;
127}
128
129pub trait ValidateNapiValue: FromNapiValue + TypeName {
130 /// # Safety
131 ///
132 /// this function called to validate whether napi value passed to rust is valid type
133 /// The reason why this function return `napi_value` is that if a `Promise<T>` passed in
134 /// we need to return `Promise.reject(T)`, not the `T`.
135 /// So we need to create `Promise.reject(T)` in this function.
136 unsafe fn validate(env: sys::napi_env, napi_val: sys::napi_value) -> Result<sys::napi_value> {
137 let value_type = Self::value_type();
138 if value_type == ValueType::Unknown {
139 return Ok(ptr::null_mut());
140 }
141
142 let mut result = -1;
143 check_status!(
144 unsafe { sys::napi_typeof(env, napi_val, &mut result) },
145 "Failed to detect napi value type",
146 )?;
147
148 let received_type = ValueType::from(result);
149 if value_type == received_type {
150 Ok(ptr::null_mut())
151 } else {
152 Err(Error::new(
153 Status::InvalidArg,
154 format!(
155 "Expect value to be {}, but received {}",
156 value_type, received_type
157 ),
158 ))
159 }
160 }
161}
162
163impl<T: TypeName> TypeName for Option<T> {
164 fn type_name() -> &'static str {
165 T::type_name()
166 }
167
168 fn value_type() -> ValueType {
169 T::value_type()
170 }
171}
172
173impl<T: ValidateNapiValue> ValidateNapiValue for Option<T> {
174 unsafe fn validate(env: sys::napi_env, napi_val: sys::napi_value) -> Result<sys::napi_value> {
175 let mut result = -1;
176 check_status!(
177 unsafe { sys::napi_typeof(env, napi_val, &mut result) },
178 "Failed to detect napi value type",
179 )?;
180
181 let received_type = ValueType::from(result);
182 if received_type == ValueType::Null || received_type == ValueType::Undefined {
183 Ok(ptr::null_mut())
184 } else if let Ok(validate_ret) = unsafe { T::validate(env, napi_val) } {
185 Ok(validate_ret)
186 } else {
187 Err(Error::new(
188 Status::InvalidArg,
189 format!(
190 "Expect value to be Option<{}>, but received {}",
191 T::value_type(),
192 received_type
193 ),
194 ))
195 }
196 }
197}
198
199impl<T> FromNapiValue for Option<T>
200where
201 T: FromNapiValue,
202{
203 unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
204 let mut val_type: i32 = 0;
205
206 check_status!(
207 unsafe { sys::napi_typeof(env, napi_val, &mut val_type) },
208 "Failed to convert napi value into rust type `Option<T>`",
209 )?;
210
211 match val_type {
212 sys::ValueType::napi_undefined | sys::ValueType::napi_null => Ok(None),
213 _ => Ok(Some(unsafe { T::from_napi_value(env, napi_val)? })),
214 }
215 }
216}
217
218impl<T> ToNapiValue for Option<T>
219where
220 T: ToNapiValue,
221{
222 unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
223 match val {
224 Some(val: T) => unsafe { T::to_napi_value(env, val) },
225 None => {
226 let mut ptr: *mut napi_value__ = ptr::null_mut();
227 check_status!(
228 unsafe { sys::napi_get_null(env, &mut ptr) },
229 "Failed to convert rust type `Option<T>` into napi value",
230 )?;
231 Ok(ptr)
232 }
233 }
234 }
235}
236
237impl<T> ToNapiValue for Result<T>
238where
239 T: ToNapiValue,
240{
241 unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
242 match val {
243 Ok(v: T) => unsafe { T::to_napi_value(env, val:v) },
244 Err(e: Error) => {
245 let error_code: *mut napi_value__ = unsafe { String::to_napi_value(env, val:format!("{:?}", e.status))? };
246 let reason: *mut napi_value__ = unsafe { String::to_napi_value(env, val:e.reason.clone())? };
247 let mut error: *mut napi_value__ = ptr::null_mut();
248 check_status!(
249 unsafe { sys::napi_create_error(env, error_code, reason, &mut error) },
250 "Failed to create napi error"
251 )?;
252
253 Ok(error)
254 }
255 }
256 }
257}
258
259impl<T: TypeName> TypeName for Rc<T> {
260 fn type_name() -> &'static str {
261 T::type_name()
262 }
263
264 fn value_type() -> ValueType {
265 T::value_type()
266 }
267}
268
269impl<T: ValidateNapiValue> ValidateNapiValue for Rc<T> {
270 unsafe fn validate(env: sys::napi_env, napi_val: sys::napi_value) -> Result<sys::napi_value> {
271 let mut result: i32 = -1;
272 check_status!(
273 unsafe { sys::napi_typeof(env, napi_val, &mut result) },
274 "Failed to detect napi value type",
275 )?;
276
277 let received_type: ValueType = ValueType::from(result);
278 if let Ok(validate_ret: *mut napi_value__) = unsafe { T::validate(env, napi_val) } {
279 Ok(validate_ret)
280 } else {
281 Err(Error::new(
282 Status::InvalidArg,
283 reason:format!(
284 "Expect value to be Rc<{}>, but received {}",
285 T::value_type(),
286 received_type
287 ),
288 ))
289 }
290 }
291}
292
293impl<T> FromNapiValue for Rc<T>
294where
295 T: FromNapiValue,
296{
297 unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
298 let mut val_type: i32 = 0;
299
300 check_status!(
301 unsafe { sys::napi_typeof(env, napi_val, &mut val_type) },
302 "Failed to convert napi value into rust type `Rc<T>`",
303 )?;
304
305 Ok(Rc::new(unsafe { T::from_napi_value(env, napi_val)? }))
306 }
307}
308
309impl<T> ToNapiValue for Rc<T>
310where
311 T: ToNapiValue + Clone,
312{
313 unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
314 unsafe { T::to_napi_value(env, (*val).clone()) }
315 }
316}
317
318impl<T: TypeName> TypeName for Arc<T> {
319 fn type_name() -> &'static str {
320 T::type_name()
321 }
322
323 fn value_type() -> ValueType {
324 T::value_type()
325 }
326}
327
328impl<T: ValidateNapiValue> ValidateNapiValue for Arc<T> {
329 unsafe fn validate(env: sys::napi_env, napi_val: sys::napi_value) -> Result<sys::napi_value> {
330 let mut result: i32 = -1;
331 check_status!(
332 unsafe { sys::napi_typeof(env, napi_val, &mut result) },
333 "Failed to detect napi value type",
334 )?;
335
336 let received_type: ValueType = ValueType::from(result);
337 if let Ok(validate_ret: *mut napi_value__) = unsafe { T::validate(env, napi_val) } {
338 Ok(validate_ret)
339 } else {
340 Err(Error::new(
341 Status::InvalidArg,
342 reason:format!(
343 "Expect value to be Arc<{}>, but received {}",
344 T::value_type(),
345 received_type
346 ),
347 ))
348 }
349 }
350}
351
352impl<T> FromNapiValue for Arc<T>
353where
354 T: FromNapiValue,
355{
356 unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
357 let mut val_type: i32 = 0;
358
359 check_status!(
360 unsafe { sys::napi_typeof(env, napi_val, &mut val_type) },
361 "Failed to convert napi value into rust type `Arc<T>`",
362 )?;
363
364 Ok(Arc::new(data:unsafe { T::from_napi_value(env, napi_val)? }))
365 }
366}
367
368impl<T> ToNapiValue for Arc<T>
369where
370 T: ToNapiValue + Clone,
371{
372 unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
373 unsafe { T::to_napi_value(env, (*val).clone()) }
374 }
375}
376
377impl<T: TypeName> TypeName for Mutex<T> {
378 fn type_name() -> &'static str {
379 T::type_name()
380 }
381
382 fn value_type() -> ValueType {
383 T::value_type()
384 }
385}
386
387impl<T: ValidateNapiValue> ValidateNapiValue for Mutex<T> {
388 unsafe fn validate(env: sys::napi_env, napi_val: sys::napi_value) -> Result<sys::napi_value> {
389 let mut result: i32 = -1;
390 check_status!(
391 unsafe { sys::napi_typeof(env, napi_val, &mut result) },
392 "Failed to detect napi value type",
393 )?;
394
395 let received_type: ValueType = ValueType::from(result);
396 if let Ok(validate_ret: *mut napi_value__) = unsafe { T::validate(env, napi_val) } {
397 Ok(validate_ret)
398 } else {
399 Err(Error::new(
400 Status::InvalidArg,
401 reason:format!(
402 "Expect value to be Mutex<{}>, but received {}",
403 T::value_type(),
404 received_type
405 ),
406 ))
407 }
408 }
409}
410
411impl<T> FromNapiValue for Mutex<T>
412where
413 T: FromNapiValue,
414{
415 unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
416 let mut val_type: i32 = 0;
417
418 check_status!(
419 unsafe { sys::napi_typeof(env, napi_val, &mut val_type) },
420 "Failed to convert napi value into rust type `Mutex<T>`",
421 )?;
422
423 Ok(Mutex::new(unsafe { T::from_napi_value(env, napi_val)? }))
424 }
425}
426
427impl<T> ToNapiValue for Mutex<T>
428where
429 T: ToNapiValue + Clone,
430{
431 unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
432 unsafe {
433 match val.lock() {
434 Ok(inner: MutexGuard<'_, T>) => T::to_napi_value(env, val:inner.clone()),
435 Err(_) => Err(Error::new(
436 Status::GenericFailure,
437 reason:"Failed to acquire a lock",
438 )),
439 }
440 }
441 }
442}
443