napi/js_values/
unknown.rs

1use std::ptr;
2
3use crate::{
4  bindgen_runtime::{Env, FromNapiValue, ToNapiValue, TypeName, ValidateNapiValue},
5  check_status, sys, type_of, JsValue, Result, Value, ValueType,
6};
7
8#[derive(Clone, Copy)]
9/// Represents a raw JavaScript value
10pub struct Unknown<'env>(
11  pub(crate) Value,
12  pub(crate) std::marker::PhantomData<&'env ()>,
13);
14
15impl<'env> JsValue<'env> for Unknown<'env> {
16  fn value(&self) -> Value {
17    self.0
18  }
19}
20
21impl TypeName for Unknown<'_> {
22  fn type_name() -> &'static str {
23    "unknown"
24  }
25
26  fn value_type() -> ValueType {
27    ValueType::Unknown
28  }
29}
30
31impl ValidateNapiValue for Unknown<'_> {
32  unsafe fn validate(
33    _env: napi_sys::napi_env,
34    _napi_val: napi_sys::napi_value,
35  ) -> Result<sys::napi_value> {
36    Ok(ptr::null_mut())
37  }
38}
39
40impl FromNapiValue for Unknown<'_> {
41  unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
42    Ok(Unknown(
43      Value {
44        env,
45        value: napi_val,
46        value_type: ValueType::Unknown,
47      },
48      std::marker::PhantomData,
49    ))
50  }
51}
52
53impl Unknown<'_> {
54  pub fn get_type(&self) -> Result<ValueType> {
55    type_of!(self.0.env, self.0.value)
56  }
57
58  /// # Safety
59  ///
60  /// This function should be called after `JsUnknown::get_type`
61  ///
62  /// And the `V` must be match with the return value of `get_type`
63  pub unsafe fn cast<V>(&self) -> Result<V>
64  where
65    V: FromNapiValue,
66  {
67    unsafe { V::from_napi_value(self.0.env, self.0.value) }
68  }
69
70  /// # Safety
71  ///
72  /// Unknown doesn't have a type
73  pub unsafe fn from_raw_unchecked(env: sys::napi_env, value: sys::napi_value) -> Self {
74    Unknown(
75      Value {
76        env,
77        value,
78        value_type: ValueType::Unknown,
79      },
80      std::marker::PhantomData,
81    )
82  }
83
84  /// Create a reference to the unknown value
85  pub fn create_ref(&self) -> Result<UnknownRef> {
86    let mut ref_ = ptr::null_mut();
87    check_status!(
88      unsafe { sys::napi_create_reference(self.0.env, self.0.value, 1, &mut ref_) },
89      "Failed to create reference"
90    )?;
91    Ok(UnknownRef { inner: ref_ })
92  }
93}
94
95/// A reference to a unknown JavaScript value.
96///
97/// You must call the `unref` method to release the reference, or the object under the hood will be leaked forever.
98///
99/// Set the `LEAK_CHECK` to `false` to disable the leak check during the `Drop`
100pub struct UnknownRef<const LEAK_CHECK: bool = true> {
101  pub(crate) inner: sys::napi_ref,
102}
103
104unsafe impl<const LEAK_CHECK: bool> Send for UnknownRef<LEAK_CHECK> {}
105
106impl<const LEAK_CHECK: bool> Drop for UnknownRef<LEAK_CHECK> {
107  fn drop(&mut self) {
108    if LEAK_CHECK && !self.inner.is_null() {
109      eprintln!("ObjectRef is not unref, it considered as a memory leak");
110    }
111  }
112}
113
114impl<const LEAK_CHECK: bool> UnknownRef<LEAK_CHECK> {
115  /// Get the object from the reference
116  pub fn get_value<'env>(&self, env: &'env Env) -> Result<Unknown<'env>> {
117    let mut result = ptr::null_mut();
118    check_status!(
119      unsafe { sys::napi_get_reference_value(env.0, self.inner, &mut result) },
120      "Failed to get reference value"
121    )?;
122    Ok(unsafe { Unknown::from_raw_unchecked(env.0, result) })
123  }
124
125  /// Unref the reference
126  pub fn unref(mut self, env: &Env) -> Result<()> {
127    check_status!(
128      unsafe { sys::napi_reference_unref(env.0, self.inner, &mut 0) },
129      "unref Ref failed"
130    )?;
131    check_status!(
132      unsafe { sys::napi_delete_reference(env.0, self.inner) },
133      "delete Ref failed"
134    )?;
135    self.inner = ptr::null_mut();
136    Ok(())
137  }
138}
139
140impl<const LEAK_CHECK: bool> FromNapiValue for UnknownRef<LEAK_CHECK> {
141  unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
142    let mut ref_ = ptr::null_mut();
143    check_status!(
144      unsafe { sys::napi_create_reference(env, napi_val, 1, &mut ref_) },
145      "Failed to create reference"
146    )?;
147    Ok(Self { inner: ref_ })
148  }
149}
150
151impl<const LEAK_CHECK: bool> ToNapiValue for &UnknownRef<LEAK_CHECK> {
152  unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
153    let mut result = ptr::null_mut();
154    check_status!(
155      unsafe { sys::napi_get_reference_value(env, val.inner, &mut result) },
156      "Failed to get reference value"
157    )?;
158    Ok(result)
159  }
160}
161
162impl<const LEAK_CHECK: bool> ToNapiValue for UnknownRef<LEAK_CHECK> {
163  unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
164    let mut result = ptr::null_mut();
165    check_status!(
166      unsafe { sys::napi_get_reference_value(env, val.inner, &mut result) },
167      "Failed to get reference value"
168    )?;
169    check_status!(
170      unsafe { sys::napi_delete_reference(env, val.inner) },
171      "Failed to delete reference"
172    )?;
173    Ok(result)
174  }
175}