napi/bindgen_runtime/
js_values.rs

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