napi_h/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;
27#[cfg(feature = "serde-json")]
28mod serde;
29mod string;
30mod symbol;
31mod task;
32mod value_ref;
33
34pub use crate::js_values::JsUnknown as Unknown;
35#[cfg(feature = "napi5")]
36pub use crate::JsDate as Date;
37pub use array::*;
38pub use arraybuffer::*;
39#[cfg(feature = "napi6")]
40pub use bigint::*;
41pub use buffer::*;
42pub use class::*;
43pub use either::*;
44pub use external::*;
45pub use function::*;
46pub use nil::*;
47pub use object::*;
48#[cfg(all(feature = "tokio_rt", feature = "napi4"))]
49pub use promise::*;
50pub use string::*;
51pub use symbol::*;
52pub use task::*;
53pub use value_ref::*;
54
55#[cfg(feature = "latin1")]
56pub use string::latin1_string::*;
57
58pub trait TypeName {
59  fn type_name() -> &'static str;
60
61  fn value_type() -> ValueType;
62}
63
64pub trait ToNapiValue {
65  /// # Safety
66  ///
67  /// this function called to convert rust values to napi values
68  unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value>;
69}
70
71impl TypeName for JsUnknown {
72  fn type_name() -> &'static str {
73    "unknown"
74  }
75
76  fn value_type() -> ValueType {
77    ValueType::Unknown
78  }
79}
80
81impl ValidateNapiValue for JsUnknown {}
82
83impl ToNapiValue for sys::napi_value {
84  unsafe fn to_napi_value(_env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
85    Ok(val)
86  }
87}
88
89impl<T: NapiRaw> ToNapiValue for T {
90  unsafe fn to_napi_value(_env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
91    Ok(unsafe { NapiRaw::raw(&val) })
92  }
93}
94
95impl<T: NapiValue> FromNapiValue for T {
96  unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
97    Ok(unsafe { T::from_raw_unchecked(env, napi_val) })
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: JsUnknown) -> 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: FromNapiValue + 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    if value_type == ValueType::Unknown {
139      return Ok(ptr::null_mut());
140    }
141
142    let mut result = -1;
143    check_status!(
144      unsafe { sys::napi_typeof(env, napi_val, &mut result) },
145      "Failed to detect napi value type",
146    )?;
147
148    let received_type = ValueType::from(result);
149    if value_type == received_type {
150      Ok(ptr::null_mut())
151    } else {
152      Err(Error::new(
153        Status::InvalidArg,
154        format!(
155          "Expect value to be {}, but received {}",
156          value_type, received_type
157        ),
158      ))
159    }
160  }
161}
162
163impl<T: TypeName> TypeName for Option<T> {
164  fn type_name() -> &'static str {
165    T::type_name()
166  }
167
168  fn value_type() -> ValueType {
169    T::value_type()
170  }
171}
172
173impl<T: ValidateNapiValue> ValidateNapiValue for Option<T> {
174  unsafe fn validate(env: sys::napi_env, napi_val: sys::napi_value) -> Result<sys::napi_value> {
175    let mut result = -1;
176    check_status!(
177      unsafe { sys::napi_typeof(env, napi_val, &mut result) },
178      "Failed to detect napi value type",
179    )?;
180
181    let received_type = ValueType::from(result);
182    if received_type == ValueType::Null || received_type == ValueType::Undefined {
183      Ok(ptr::null_mut())
184    } else if let Ok(validate_ret) = unsafe { T::validate(env, napi_val) } {
185      Ok(validate_ret)
186    } else {
187      Err(Error::new(
188        Status::InvalidArg,
189        format!(
190          "Expect value to be Option<{}>, but received {}",
191          T::value_type(),
192          received_type
193        ),
194      ))
195    }
196  }
197}
198
199impl<T> FromNapiValue for Option<T>
200where
201  T: FromNapiValue,
202{
203  unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
204    let mut val_type = 0;
205
206    check_status!(
207      unsafe { sys::napi_typeof(env, napi_val, &mut val_type) },
208      "Failed to convert napi value into rust type `Option<T>`",
209    )?;
210
211    match val_type {
212      sys::ValueType::napi_undefined | sys::ValueType::napi_null => Ok(None),
213      _ => Ok(Some(unsafe { T::from_napi_value(env, napi_val)? })),
214    }
215  }
216}
217
218impl<T> ToNapiValue for Option<T>
219where
220  T: ToNapiValue,
221{
222  unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
223    match val {
224      Some(val) => unsafe { T::to_napi_value(env, val) },
225      None => {
226        let mut ptr = ptr::null_mut();
227        check_status!(
228          unsafe { sys::napi_get_null(env, &mut ptr) },
229          "Failed to convert rust type `Option<T>` into napi value",
230        )?;
231        Ok(ptr)
232      }
233    }
234  }
235}
236
237impl<T> ToNapiValue for Result<T>
238where
239  T: ToNapiValue,
240{
241  unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
242    match val {
243      Ok(v) => unsafe { T::to_napi_value(env, v) },
244      Err(e) => {
245        let error_code = unsafe { String::to_napi_value(env, format!("{:?}", e.status))? };
246        let reason = unsafe { String::to_napi_value(env, e.reason.clone())? };
247        let mut error = ptr::null_mut();
248        check_status!(
249          unsafe { sys::napi_create_error(env, error_code, reason, &mut error) },
250          "Failed to create napi error"
251        )?;
252
253        Ok(error)
254      }
255    }
256  }
257}
258
259impl<T: TypeName> TypeName for Rc<T> {
260  fn type_name() -> &'static str {
261    T::type_name()
262  }
263
264  fn value_type() -> ValueType {
265    T::value_type()
266  }
267}
268
269impl<T: ValidateNapiValue> ValidateNapiValue for Rc<T> {
270  unsafe fn validate(env: sys::napi_env, napi_val: sys::napi_value) -> Result<sys::napi_value> {
271    let mut result = -1;
272    check_status!(
273      unsafe { sys::napi_typeof(env, napi_val, &mut result) },
274      "Failed to detect napi value type",
275    )?;
276
277    let received_type = ValueType::from(result);
278    if let Ok(validate_ret) = unsafe { T::validate(env, napi_val) } {
279      Ok(validate_ret)
280    } else {
281      Err(Error::new(
282        Status::InvalidArg,
283        format!(
284          "Expect value to be Rc<{}>, but received {}",
285          T::value_type(),
286          received_type
287        ),
288      ))
289    }
290  }
291}
292
293impl<T> FromNapiValue for Rc<T>
294where
295  T: FromNapiValue,
296{
297  unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
298    let mut val_type = 0;
299
300    check_status!(
301      unsafe { sys::napi_typeof(env, napi_val, &mut val_type) },
302      "Failed to convert napi value into rust type `Rc<T>`",
303    )?;
304
305    Ok(Rc::new(unsafe { T::from_napi_value(env, napi_val)? }))
306  }
307}
308
309impl<T> ToNapiValue for Rc<T>
310where
311  T: ToNapiValue + Clone,
312{
313  unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
314    unsafe { T::to_napi_value(env, (*val).clone()) }
315  }
316}
317
318impl<T: TypeName> TypeName for Arc<T> {
319  fn type_name() -> &'static str {
320    T::type_name()
321  }
322
323  fn value_type() -> ValueType {
324    T::value_type()
325  }
326}
327
328impl<T: ValidateNapiValue> ValidateNapiValue for Arc<T> {
329  unsafe fn validate(env: sys::napi_env, napi_val: sys::napi_value) -> Result<sys::napi_value> {
330    let mut result = -1;
331    check_status!(
332      unsafe { sys::napi_typeof(env, napi_val, &mut result) },
333      "Failed to detect napi value type",
334    )?;
335
336    let received_type = ValueType::from(result);
337    if let Ok(validate_ret) = unsafe { T::validate(env, napi_val) } {
338      Ok(validate_ret)
339    } else {
340      Err(Error::new(
341        Status::InvalidArg,
342        format!(
343          "Expect value to be Arc<{}>, but received {}",
344          T::value_type(),
345          received_type
346        ),
347      ))
348    }
349  }
350}
351
352impl<T> FromNapiValue for Arc<T>
353where
354  T: FromNapiValue,
355{
356  unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
357    let mut val_type = 0;
358
359    check_status!(
360      unsafe { sys::napi_typeof(env, napi_val, &mut val_type) },
361      "Failed to convert napi value into rust type `Arc<T>`",
362    )?;
363
364    Ok(Arc::new(unsafe { T::from_napi_value(env, napi_val)? }))
365  }
366}
367
368impl<T> ToNapiValue for Arc<T>
369where
370  T: ToNapiValue + Clone,
371{
372  unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
373    unsafe { T::to_napi_value(env, (*val).clone()) }
374  }
375}
376
377impl<T: TypeName> TypeName for Mutex<T> {
378  fn type_name() -> &'static str {
379    T::type_name()
380  }
381
382  fn value_type() -> ValueType {
383    T::value_type()
384  }
385}
386
387impl<T: ValidateNapiValue> ValidateNapiValue for Mutex<T> {
388  unsafe fn validate(env: sys::napi_env, napi_val: sys::napi_value) -> Result<sys::napi_value> {
389    let mut result = -1;
390    check_status!(
391      unsafe { sys::napi_typeof(env, napi_val, &mut result) },
392      "Failed to detect napi value type",
393    )?;
394
395    let received_type = ValueType::from(result);
396    if let Ok(validate_ret) = unsafe { T::validate(env, napi_val) } {
397      Ok(validate_ret)
398    } else {
399      Err(Error::new(
400        Status::InvalidArg,
401        format!(
402          "Expect value to be Mutex<{}>, but received {}",
403          T::value_type(),
404          received_type
405        ),
406      ))
407    }
408  }
409}
410
411impl<T> FromNapiValue for Mutex<T>
412where
413  T: FromNapiValue,
414{
415  unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
416    let mut val_type = 0;
417
418    check_status!(
419      unsafe { sys::napi_typeof(env, napi_val, &mut val_type) },
420      "Failed to convert napi value into rust type `Mutex<T>`",
421    )?;
422
423    Ok(Mutex::new(unsafe { T::from_napi_value(env, napi_val)? }))
424  }
425}
426
427impl<T> ToNapiValue for Mutex<T>
428where
429  T: ToNapiValue + Clone,
430{
431  unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
432    unsafe {
433      match val.lock() {
434        Ok(inner) => T::to_napi_value(env, inner.clone()),
435        Err(_) => Err(Error::new(
436          Status::GenericFailure,
437          "Failed to acquire a lock",
438        )),
439      }
440    }
441  }
442}