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