use std::ptr;
use crate::{
bindgen_runtime::{Env, FromNapiValue, ToNapiValue, TypeName, ValidateNapiValue},
check_status, sys, JsValue, Result, Value, ValueType,
};
#[derive(Clone, Copy)]
pub struct JsSymbol<'env>(
pub(crate) Value,
pub(crate) std::marker::PhantomData<&'env ()>,
);
impl TypeName for JsSymbol<'_> {
fn type_name() -> &'static str {
"symbol"
}
fn value_type() -> ValueType {
ValueType::Symbol
}
}
impl<'env> JsValue<'env> for JsSymbol<'env> {
fn value(&self) -> Value {
self.0
}
}
impl FromNapiValue for JsSymbol<'_> {
unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
Ok(JsSymbol(
Value {
env,
value: napi_val,
value_type: ValueType::Symbol,
},
std::marker::PhantomData,
))
}
}
impl ValidateNapiValue for JsSymbol<'_> {}
impl JsSymbol<'_> {
pub fn create_ref<const LEAK_CHECK: bool>(&self) -> Result<SymbolRef<LEAK_CHECK>> {
let mut ref_ = ptr::null_mut();
check_status!(
unsafe { sys::napi_create_reference(self.0.env, self.0.value, 1, &mut ref_) },
"Failed to create reference"
)?;
Ok(SymbolRef { inner: ref_ })
}
}
pub struct SymbolRef<const LEAK_CHECK: bool = true> {
pub(crate) inner: sys::napi_ref,
}
unsafe impl<const LEAK_CHECK: bool> Send for SymbolRef<LEAK_CHECK> {}
impl<const LEAK_CHECK: bool> Drop for SymbolRef<LEAK_CHECK> {
fn drop(&mut self) {
if LEAK_CHECK && !self.inner.is_null() {
eprintln!("ObjectRef is not unref, it considered as a memory leak");
}
}
}
impl<const LEAK_CHECK: bool> SymbolRef<LEAK_CHECK> {
pub fn get_value<'env>(&self, env: &'env Env) -> Result<JsSymbol<'env>> {
let mut result = ptr::null_mut();
check_status!(
unsafe { sys::napi_get_reference_value(env.0, self.inner, &mut result) },
"Failed to get reference value"
)?;
unsafe { JsSymbol::from_napi_value(env.0, result) }
}
pub fn unref(mut self, env: &Env) -> Result<()> {
check_status!(
unsafe { sys::napi_delete_reference(env.0, self.inner) },
"delete Ref failed"
)?;
self.inner = ptr::null_mut();
Ok(())
}
}
impl<const LEAK_CHECK: bool> FromNapiValue for SymbolRef<LEAK_CHECK> {
unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
let mut ref_ = ptr::null_mut();
check_status!(
unsafe { sys::napi_create_reference(env, napi_val, 1, &mut ref_) },
"Failed to create reference"
)?;
Ok(Self { inner: ref_ })
}
}
impl<const LEAK_CHECK: bool> ToNapiValue for &SymbolRef<LEAK_CHECK> {
unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
let mut result = ptr::null_mut();
check_status!(
unsafe { sys::napi_get_reference_value(env, val.inner, &mut result) },
"Failed to get reference value"
)?;
Ok(result)
}
}
impl<const LEAK_CHECK: bool> ToNapiValue for SymbolRef<LEAK_CHECK> {
unsafe fn to_napi_value(env: sys::napi_env, mut val: Self) -> Result<sys::napi_value> {
let mut result = ptr::null_mut();
check_status!(
unsafe { sys::napi_get_reference_value(env, val.inner, &mut result) },
"Failed to get reference value"
)?;
check_status!(
unsafe { sys::napi_delete_reference(env, val.inner) },
"delete Ref failed"
)?;
val.inner = ptr::null_mut();
drop(val);
Ok(result)
}
}