napi/js_values/
value_ref.rs

1use std::{marker::PhantomData, ptr};
2
3use crate::{
4  bindgen_runtime::{FromNapiMutRef, FromNapiValue, ToNapiValue},
5  check_status, sys, Env, JsValue, Result,
6};
7
8pub struct Ref<T> {
9  pub(crate) raw_ref: sys::napi_ref,
10  pub(crate) _phantom: PhantomData<T>,
11  pub(crate) taken: bool,
12}
13
14#[allow(clippy::non_send_fields_in_send_ty)]
15unsafe impl<T> Send for Ref<T> {}
16unsafe impl<T> Sync for Ref<T> {}
17
18impl<'env, T: JsValue<'env>> Ref<T> {
19  pub fn new(env: &Env, value: &T) -> Result<Ref<T>> {
20    let mut raw_ref = ptr::null_mut();
21    check_status!(
22      unsafe { sys::napi_create_reference(env.0, value.raw(), 1, &mut raw_ref) },
23      "Create napi_ref from {} failed",
24      std::any::type_name::<T>()
25    )?;
26    Ok(Ref {
27      raw_ref,
28      taken: false,
29      _phantom: PhantomData,
30    })
31  }
32
33  pub fn unref(&mut self, env: &Env) -> Result<()> {
34    check_status!(
35      unsafe { sys::napi_reference_unref(env.0, self.raw_ref, &mut 0) },
36      "unref Ref failed"
37    )?;
38
39    check_status!(
40      unsafe { sys::napi_delete_reference(env.0, self.raw_ref) },
41      "delete Ref failed"
42    )?;
43    self.taken = true;
44    Ok(())
45  }
46}
47
48impl<T: FromNapiValue> Ref<T> {
49  /// Get the value from the reference
50  pub fn get_value(&self, env: &Env) -> Result<T> {
51    if self.taken {
52      return Err(crate::Error::new(
53        crate::Status::InvalidArg,
54        "Ref value has been deleted",
55      ));
56    }
57    let mut result = ptr::null_mut();
58    check_status!(
59      unsafe { sys::napi_get_reference_value(env.0, self.raw_ref, &mut result) },
60      "Failed to get reference value"
61    )?;
62    unsafe { T::from_napi_value(env.0, result) }
63  }
64}
65
66impl<T: 'static + FromNapiMutRef> Ref<T> {
67  /// Get the value reference from the reference
68  #[allow(clippy::mut_from_ref)]
69  pub fn get_value_mut(&self, env: &Env) -> Result<&mut T> {
70    let mut result = ptr::null_mut();
71    check_status!(
72      unsafe { sys::napi_get_reference_value(env.0, self.raw_ref, &mut result) },
73      "Failed to get reference value"
74    )?;
75    unsafe { T::from_napi_mut_ref(env.0, result) }
76  }
77}
78
79impl<'env, T: FromNapiValue + JsValue<'env>> FromNapiValue for Ref<T> {
80  unsafe fn from_napi_value(env: sys::napi_env, value: sys::napi_value) -> Result<Self> {
81    let val = T::from_napi_value(env, value)?;
82    Ref::new(&Env::from_raw(env), &val)
83  }
84}
85
86impl<T: 'static> ToNapiValue for Ref<T> {
87  unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
88    let mut result = ptr::null_mut();
89    check_status!(
90      unsafe { sys::napi_get_reference_value(env, val.raw_ref, &mut result) },
91      "Failed to get reference value"
92    )?;
93    Ok(result)
94  }
95}