napi/js_values/
external.rs

1use std::{marker::PhantomData, ptr};
2
3use crate::{
4  bindgen_prelude::{
5    sys, External, ExternalRef, FromNapiValue, Result, Status, TypeName, ValidateNapiValue,
6  },
7  check_status, Error, JsValue, Value, ValueType,
8};
9
10/// Represent the Node-API `External` value
11///
12/// The difference between the `JsExternal` and `External` is that the `JsExternal` holds the raw value of `External`.
13/// So that you can call `Object::set_property` with the `JsExternal` value, but can't do the same with `External`.
14pub struct JsExternal<'env>(pub(crate) Value, PhantomData<&'env ()>);
15
16impl<'env> TypeName for JsExternal<'env> {
17  fn type_name() -> &'static str {
18    "External"
19  }
20
21  fn value_type() -> ValueType {
22    ValueType::External
23  }
24}
25
26impl<'env> ValidateNapiValue for JsExternal<'env> {}
27
28impl<'env> FromNapiValue for JsExternal<'env> {
29  unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
30    Ok(Self(
31      Value {
32        env,
33        value: napi_val,
34        value_type: ValueType::External,
35      },
36      PhantomData,
37    ))
38  }
39}
40
41impl<'env> JsValue<'env> for JsExternal<'env> {
42  fn value(&self) -> Value {
43    self.0
44  }
45}
46
47impl<'env> JsExternal<'env> {
48  /// Get the value from the `JsExternal`
49  ///
50  /// If the underlying value is not `T`, it will return `InvalidArg` error.
51  pub fn get_value<T: 'static>(&self) -> Result<&mut T> {
52    self.get_static_value::<T>().map(|ext| ext.as_mut())
53  }
54
55  /// Create a reference to the `JsExternal`
56  ///
57  /// If the underlying value is not `T`, it will return `InvalidArg` error.
58  pub fn create_ref<T: 'static>(&self) -> Result<ExternalRef<T>> {
59    let mut ref_ = ptr::null_mut();
60    let external = self.get_static_value()?;
61    check_status!(
62      unsafe { sys::napi_create_reference(self.0.env, self.0.value, 1, &mut ref_) },
63      "Failed to create reference on external value"
64    )?;
65    Ok(ExternalRef {
66      obj: external,
67      raw: ref_,
68      env: self.0.env,
69    })
70  }
71
72  #[inline]
73  fn get_static_value<T: 'static>(&self) -> Result<&'static mut External<T>> {
74    let mut unknown_tagged_object = ptr::null_mut();
75    check_status!(
76      unsafe { sys::napi_get_value_external(self.0.env, self.0.value, &mut unknown_tagged_object) },
77      "Failed to get external value"
78    )?;
79
80    match unsafe { External::from_raw_impl(unknown_tagged_object) } {
81      Some(external) => Ok(external),
82      None => Err(Error::new(
83        Status::InvalidArg,
84        format!(
85          "<{}> on `External` is not the type of wrapped object",
86          std::any::type_name::<T>()
87        ),
88      )),
89    }
90  }
91}