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;
25#[cfg(all(feature = "tokio_rt", feature = "napi4"))]
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::*;
53#[cfg(all(feature = "tokio_rt", feature = "napi4"))]
54pub use promise::*;
55pub use promise_raw::*;
56pub use scope::*;
57#[cfg(feature = "web_stream")]
58pub use stream::*;
59pub use string::*;
60pub use symbol::*;
61pub use task::*;
62pub use value_ref::*;
63
64pub trait TypeName {
65  fn type_name() -> &'static str;
66
67  fn value_type() -> ValueType;
68}
69
70pub trait ToNapiValue: Sized {
71  /// # Safety
72  ///
73  /// this function called to convert rust values to napi values
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  /// # 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: Unknown) -> Result<Self> {
108    unsafe { Self::from_napi_value(value.0.env, 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: 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
139    let mut result = -1;
140    check_status!(
141      unsafe { sys::napi_typeof(env, napi_val, &mut result) },
142      "Failed to detect napi value type",
143    )?;
144
145    let received_type = ValueType::from(result);
146    if value_type == received_type {
147      Ok(ptr::null_mut())
148    } else {
149      Err(Error::new(
150        Status::InvalidArg,
151        format!("Expect value to be {value_type}, but received {received_type}"),
152      ))
153    }
154  }
155}
156
157impl<T: TypeName> TypeName for Option<T> {
158  fn type_name() -> &'static str {
159    T::type_name()
160  }
161
162  fn value_type() -> ValueType {
163    T::value_type()
164  }
165}
166
167impl<T: ValidateNapiValue> ValidateNapiValue for Option<T> {
168  unsafe fn validate(env: sys::napi_env, napi_val: sys::napi_value) -> Result<sys::napi_value> {
169    let mut result = -1;
170    check_status!(
171      unsafe { sys::napi_typeof(env, napi_val, &mut result) },
172      "Failed to detect napi value type",
173    )?;
174
175    let received_type = ValueType::from(result);
176    if received_type == ValueType::Null || received_type == ValueType::Undefined {
177      Ok(ptr::null_mut())
178    } else if let Ok(validate_ret) = unsafe { T::validate(env, napi_val) } {
179      Ok(validate_ret)
180    } else {
181      Err(Error::new(
182        Status::InvalidArg,
183        format!(
184          "Expect value to be Option<{}>, but received {}",
185          T::value_type(),
186          received_type
187        ),
188      ))
189    }
190  }
191}
192
193impl<T> FromNapiValue for Option<T>
194where
195  T: FromNapiValue,
196{
197  unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
198    let mut val_type = 0;
199
200    check_status!(
201      unsafe { sys::napi_typeof(env, napi_val, &mut val_type) },
202      "Failed to convert napi value into rust type `Option<T>`",
203    )?;
204
205    match val_type {
206      sys::ValueType::napi_undefined | sys::ValueType::napi_null => Ok(None),
207      _ => Ok(Some(unsafe { T::from_napi_value(env, napi_val)? })),
208    }
209  }
210}
211
212impl<T> ToNapiValue for Option<T>
213where
214  T: ToNapiValue,
215{
216  unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
217    match val {
218      Some(val) => unsafe { T::to_napi_value(env, val) },
219      None => {
220        let mut ptr = ptr::null_mut();
221        check_status!(
222          unsafe { sys::napi_get_null(env, &mut ptr) },
223          "Failed to convert rust type `Option<T>` into napi value",
224        )?;
225        Ok(ptr)
226      }
227    }
228  }
229}
230
231impl<T> ToNapiValue for Result<T>
232where
233  T: ToNapiValue,
234{
235  unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
236    match val {
237      Ok(v) => unsafe { T::to_napi_value(env, v) },
238      Err(e) => {
239        let error_code = unsafe { String::to_napi_value(env, format!("{:?}", e.status))? };
240        let reason = unsafe { String::to_napi_value(env, e.reason.clone())? };
241        let mut error = ptr::null_mut();
242        check_status!(
243          unsafe { sys::napi_create_error(env, error_code, reason, &mut error) },
244          "Failed to create napi error"
245        )?;
246
247        Ok(error)
248      }
249    }
250  }
251}
252
253impl<T: TypeName> TypeName for Rc<T> {
254  fn type_name() -> &'static str {
255    T::type_name()
256  }
257
258  fn value_type() -> ValueType {
259    T::value_type()
260  }
261}
262
263impl<T: ValidateNapiValue> ValidateNapiValue for Rc<T> {
264  unsafe fn validate(env: sys::napi_env, napi_val: sys::napi_value) -> Result<sys::napi_value> {
265    let mut result = -1;
266    check_status!(
267      unsafe { sys::napi_typeof(env, napi_val, &mut result) },
268      "Failed to detect napi value type",
269    )?;
270
271    let received_type = ValueType::from(result);
272    if let Ok(validate_ret) = unsafe { T::validate(env, napi_val) } {
273      Ok(validate_ret)
274    } else {
275      Err(Error::new(
276        Status::InvalidArg,
277        format!(
278          "Expect value to be Rc<{}>, but received {}",
279          T::value_type(),
280          received_type
281        ),
282      ))
283    }
284  }
285}
286
287impl<T> FromNapiValue for Rc<T>
288where
289  T: FromNapiValue,
290{
291  unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
292    let mut val_type = 0;
293
294    check_status!(
295      unsafe { sys::napi_typeof(env, napi_val, &mut val_type) },
296      "Failed to convert napi value into rust type `Rc<T>`",
297    )?;
298
299    Ok(Rc::new(unsafe { T::from_napi_value(env, napi_val)? }))
300  }
301}
302
303impl<T> ToNapiValue for Rc<T>
304where
305  T: ToNapiValue + Clone,
306{
307  unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
308    unsafe { T::to_napi_value(env, (*val).clone()) }
309  }
310}
311
312impl<T> ToNapiValue for &Rc<T>
313where
314  T: ToNapiValue + Clone,
315{
316  unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
317    unsafe { T::to_napi_value(env, (**val).clone()) }
318  }
319}
320
321impl<T> ToNapiValue for &mut Rc<T>
322where
323  T: ToNapiValue + Clone,
324{
325  unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
326    unsafe { T::to_napi_value(env, (**val).clone()) }
327  }
328}
329
330impl<T: TypeName> TypeName for Arc<T> {
331  fn type_name() -> &'static str {
332    T::type_name()
333  }
334
335  fn value_type() -> ValueType {
336    T::value_type()
337  }
338}
339
340impl<T: ValidateNapiValue> ValidateNapiValue for Arc<T> {
341  unsafe fn validate(env: sys::napi_env, napi_val: sys::napi_value) -> Result<sys::napi_value> {
342    let mut result = -1;
343    check_status!(
344      unsafe { sys::napi_typeof(env, napi_val, &mut result) },
345      "Failed to detect napi value type",
346    )?;
347
348    let received_type = ValueType::from(result);
349    if let Ok(validate_ret) = unsafe { T::validate(env, napi_val) } {
350      Ok(validate_ret)
351    } else {
352      Err(Error::new(
353        Status::InvalidArg,
354        format!(
355          "Expect value to be Arc<{}>, but received {}",
356          T::value_type(),
357          received_type
358        ),
359      ))
360    }
361  }
362}
363
364impl<T> FromNapiValue for Arc<T>
365where
366  T: FromNapiValue,
367{
368  unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
369    let mut val_type = 0;
370
371    check_status!(
372      unsafe { sys::napi_typeof(env, napi_val, &mut val_type) },
373      "Failed to convert napi value into rust type `Arc<T>`",
374    )?;
375
376    Ok(Arc::new(unsafe { T::from_napi_value(env, napi_val)? }))
377  }
378}
379
380impl<T> ToNapiValue for Arc<T>
381where
382  T: ToNapiValue + Clone,
383{
384  unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
385    unsafe { T::to_napi_value(env, (*val).clone()) }
386  }
387}
388
389impl<T> ToNapiValue for &Arc<T>
390where
391  T: ToNapiValue + Clone,
392{
393  unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
394    unsafe { T::to_napi_value(env, (**val).clone()) }
395  }
396}
397
398impl<T> ToNapiValue for &mut 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: TypeName> TypeName for Mutex<T> {
408  fn type_name() -> &'static str {
409    T::type_name()
410  }
411
412  fn value_type() -> ValueType {
413    T::value_type()
414  }
415}
416
417impl<T: ValidateNapiValue> ValidateNapiValue for Mutex<T> {
418  unsafe fn validate(env: sys::napi_env, napi_val: sys::napi_value) -> Result<sys::napi_value> {
419    let mut result = -1;
420    check_status!(
421      unsafe { sys::napi_typeof(env, napi_val, &mut result) },
422      "Failed to detect napi value type",
423    )?;
424
425    let received_type = ValueType::from(result);
426    if let Ok(validate_ret) = unsafe { T::validate(env, napi_val) } {
427      Ok(validate_ret)
428    } else {
429      Err(Error::new(
430        Status::InvalidArg,
431        format!(
432          "Expect value to be Mutex<{}>, but received {}",
433          T::value_type(),
434          received_type
435        ),
436      ))
437    }
438  }
439}
440
441impl<T> FromNapiValue for Mutex<T>
442where
443  T: FromNapiValue,
444{
445  unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
446    let mut val_type = 0;
447
448    check_status!(
449      unsafe { sys::napi_typeof(env, napi_val, &mut val_type) },
450      "Failed to convert napi value into rust type `Mutex<T>`",
451    )?;
452
453    Ok(Mutex::new(unsafe { T::from_napi_value(env, napi_val)? }))
454  }
455}
456
457impl<T> ToNapiValue for Mutex<T>
458where
459  T: ToNapiValue + Clone,
460{
461  unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
462    unsafe {
463      match val.lock() {
464        Ok(inner) => T::to_napi_value(env, inner.clone()),
465        Err(_) => Err(Error::new(
466          Status::GenericFailure,
467          "Failed to acquire a lock",
468        )),
469      }
470    }
471  }
472}
473
474impl<T> ToNapiValue for &Mutex<T>
475where
476  T: ToNapiValue + Clone,
477{
478  unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
479    unsafe {
480      match val.lock() {
481        Ok(inner) => T::to_napi_value(env, inner.clone()),
482        Err(_) => Err(Error::new(
483          Status::GenericFailure,
484          "Failed to acquire a lock",
485        )),
486      }
487    }
488  }
489}
490
491impl<T> ToNapiValue for &mut Mutex<T>
492where
493  T: ToNapiValue + Clone,
494{
495  unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
496    ToNapiValue::to_napi_value(env, &*val)
497  }
498}