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