Skip to main content

napi/bindgen_runtime/
js_values.rs

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