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  /// # 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  fn into_unknown(self, env: &Env) -> Result<Unknown<'_>> {
75    let napi_val = unsafe { Self::to_napi_value(env.0, self)? };
76    Ok(Unknown(
77      Value {
78        env: env.0,
79        value: napi_val,
80        value_type: ValueType::Unknown,
81      },
82      std::marker::PhantomData,
83    ))
84  }
85}
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<'env, T: JsValue<'env>> ToNapiValue for T {
94  unsafe fn to_napi_value(_env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
95    Ok(val.raw())
96  }
97}
98
99pub trait FromNapiValue: Sized {
100  /// # Safety
101  ///
102  /// this function called to convert napi values to native rust values
103  unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self>;
104
105  fn from_unknown(value: Unknown) -> Result<Self> {
106    unsafe { Self::from_napi_value(value.0.env, value.0.value) }
107  }
108}
109
110pub trait FromNapiRef {
111  /// # Safety
112  ///
113  /// this function called to convert napi values to native rust values
114  unsafe fn from_napi_ref(env: sys::napi_env, napi_val: sys::napi_value) -> Result<&'static Self>;
115}
116
117pub trait FromNapiMutRef {
118  /// # Safety
119  ///
120  /// this function called to convert napi values to native rust values
121  unsafe fn from_napi_mut_ref(
122    env: sys::napi_env,
123    napi_val: sys::napi_value,
124  ) -> Result<&'static mut Self>;
125}
126
127impl<T: FromNapiRef + 'static> FromNapiValue for &T {
128  unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
129    unsafe { T::from_napi_ref(env, napi_val) }
130  }
131}
132
133impl<T: FromNapiMutRef + 'static> FromNapiValue for &mut T {
134  unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
135    unsafe { T::from_napi_mut_ref(env, napi_val) }
136  }
137}
138
139pub trait ValidateNapiValue: TypeName {
140  /// # Safety
141  ///
142  /// this function called to validate whether napi value passed to rust is valid type
143  /// The reason why this function return `napi_value` is that if a `Promise<T>` passed in
144  /// we need to return `Promise.reject(T)`, not the `T`.
145  /// So we need to create `Promise.reject(T)` in this function.
146  unsafe fn validate(env: sys::napi_env, napi_val: sys::napi_value) -> Result<sys::napi_value> {
147    let value_type = Self::value_type();
148
149    let mut result = -1;
150    check_status!(
151      unsafe { sys::napi_typeof(env, napi_val, &mut result) },
152      "Failed to detect napi value type",
153    )?;
154
155    let received_type = ValueType::from(result);
156    if value_type == received_type {
157      Ok(ptr::null_mut())
158    } else {
159      Err(Error::new(
160        Status::InvalidArg,
161        format!("Expect value to be {value_type}, but received {received_type}"),
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}