napi/js_values/
symbol.rs

1use std::ptr;
2
3use crate::{
4  bindgen_runtime::{Env, FromNapiValue, ToNapiValue, TypeName, ValidateNapiValue},
5  check_status, sys, JsValue, Result, Value, ValueType,
6};
7
8#[derive(Clone, Copy)]
9/// represent `Symbol` value in JavaScript
10pub struct JsSymbol<'env>(
11  pub(crate) Value,
12  pub(crate) std::marker::PhantomData<&'env ()>,
13);
14
15impl TypeName for JsSymbol<'_> {
16  fn type_name() -> &'static str {
17    "symbol"
18  }
19
20  fn value_type() -> ValueType {
21    ValueType::Symbol
22  }
23}
24
25impl<'env> JsValue<'env> for JsSymbol<'env> {
26  fn value(&self) -> Value {
27    self.0
28  }
29}
30
31impl FromNapiValue for JsSymbol<'_> {
32  unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
33    Ok(JsSymbol(
34      Value {
35        env,
36        value: napi_val,
37        value_type: ValueType::Symbol,
38      },
39      std::marker::PhantomData,
40    ))
41  }
42}
43
44impl ValidateNapiValue for JsSymbol<'_> {}
45
46impl JsSymbol<'_> {
47  /// Create a reference to the symbol
48  pub fn create_ref<const LEAK_CHECK: bool>(&self) -> Result<SymbolRef<LEAK_CHECK>> {
49    let mut ref_ = ptr::null_mut();
50    check_status!(
51      unsafe { sys::napi_create_reference(self.0.env, self.0.value, 1, &mut ref_) },
52      "Failed to create reference"
53    )?;
54    Ok(SymbolRef { inner: ref_ })
55  }
56}
57
58/// A reference to a JavaScript Symbol.
59///
60/// You must call the `unref` method to release the reference, or the symbol under the hood will be leaked forever.
61///
62/// Set the `LEAK_CHECK` to `false` to disable the leak check during the `Drop`
63pub struct SymbolRef<const LEAK_CHECK: bool = true> {
64  pub(crate) inner: sys::napi_ref,
65}
66
67unsafe impl<const LEAK_CHECK: bool> Send for SymbolRef<LEAK_CHECK> {}
68
69impl<const LEAK_CHECK: bool> Drop for SymbolRef<LEAK_CHECK> {
70  fn drop(&mut self) {
71    if LEAK_CHECK && !self.inner.is_null() {
72      eprintln!("ObjectRef is not unref, it considered as a memory leak");
73    }
74  }
75}
76
77impl<const LEAK_CHECK: bool> SymbolRef<LEAK_CHECK> {
78  /// Get the object from the reference
79  pub fn get_value<'env>(&self, env: &'env Env) -> Result<JsSymbol<'env>> {
80    let mut result = ptr::null_mut();
81    check_status!(
82      unsafe { sys::napi_get_reference_value(env.0, self.inner, &mut result) },
83      "Failed to get reference value"
84    )?;
85    unsafe { JsSymbol::from_napi_value(env.0, result) }
86  }
87
88  /// Unref the reference
89  pub fn unref(mut self, env: &Env) -> Result<()> {
90    check_status!(
91      unsafe { sys::napi_delete_reference(env.0, self.inner) },
92      "delete Ref failed"
93    )?;
94    self.inner = ptr::null_mut();
95    Ok(())
96  }
97}
98
99impl<const LEAK_CHECK: bool> FromNapiValue for SymbolRef<LEAK_CHECK> {
100  unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
101    let mut ref_ = ptr::null_mut();
102    check_status!(
103      unsafe { sys::napi_create_reference(env, napi_val, 1, &mut ref_) },
104      "Failed to create reference"
105    )?;
106    Ok(Self { inner: ref_ })
107  }
108}
109
110impl<const LEAK_CHECK: bool> ToNapiValue for &SymbolRef<LEAK_CHECK> {
111  unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
112    let mut result = ptr::null_mut();
113    check_status!(
114      unsafe { sys::napi_get_reference_value(env, val.inner, &mut result) },
115      "Failed to get reference value"
116    )?;
117    Ok(result)
118  }
119}
120
121impl<const LEAK_CHECK: bool> ToNapiValue for SymbolRef<LEAK_CHECK> {
122  unsafe fn to_napi_value(env: sys::napi_env, mut val: Self) -> Result<sys::napi_value> {
123    let mut result = ptr::null_mut();
124    check_status!(
125      unsafe { sys::napi_get_reference_value(env, val.inner, &mut result) },
126      "Failed to get reference value"
127    )?;
128    check_status!(
129      unsafe { sys::napi_delete_reference(env, val.inner) },
130      "delete Ref failed"
131    )?;
132    val.inner = ptr::null_mut();
133    drop(val);
134    Ok(result)
135  }
136}