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