use std::any::TypeId; use std::cell::RefCell; use std::collections::HashMap; use std::ffi::c_void; use std::ops::{Deref, DerefMut}; use crate::{check_status, Error, Result, Status}; type RefInformation = (*mut c_void, crate::sys::napi_env, crate::sys::napi_ref); thread_local! { static REFERENCE_MAP: RefCell> = Default::default(); } /// ### Experimental feature /// /// Create a `reference` from `Class` instance. /// Unref the `Reference` when the `Reference` is dropped. pub struct Reference { raw: *mut T, napi_ref: crate::sys::napi_ref, env: crate::sys::napi_env, } unsafe impl Send for Reference {} unsafe impl Sync for Reference {} impl Drop for Reference { fn drop(&mut self) { let status = unsafe { crate::sys::napi_reference_unref(self.env, self.napi_ref, &mut 0) }; debug_assert!( status == crate::sys::Status::napi_ok, "Reference unref failed" ); } } impl Reference { #[doc(hidden)] pub fn add_ref(t: TypeId, value: RefInformation) { REFERENCE_MAP.with(|map| { map.borrow_mut().insert(t, value); }); } #[doc(hidden)] pub fn from_typeid(t: TypeId) -> Result { if let Some((wrapped_value, env, napi_ref)) = REFERENCE_MAP.with(|map| map.borrow().get(&t).cloned()) { check_status!( unsafe { crate::sys::napi_reference_ref(env, napi_ref, &mut 0) }, "Failed to ref napi reference" )?; Ok(Self { raw: wrapped_value as *mut T, env, napi_ref, }) } else { Err(Error::new( Status::InvalidArg, format!("Class for Type {:?} not found", t), )) } } } impl Reference { pub fn share_with Result>( self, f: F, ) -> Result> { let s = f(Box::leak(unsafe { Box::from_raw(self.raw) }))?; Ok(SharedReference { raw: Box::into_raw(Box::new(s)), owner: self, }) } } impl Deref for Reference { type Target = T; fn deref(&self) -> &Self::Target { unsafe { Box::leak(Box::from_raw(self.raw)) } } } impl DerefMut for Reference { fn deref_mut(&mut self) -> &mut Self::Target { unsafe { Box::leak(Box::from_raw(self.raw)) } } } impl Clone for Reference { fn clone(&self) -> Self { let mut ref_count = 0; let status = unsafe { crate::sys::napi_reference_ref(self.env, self.napi_ref, &mut ref_count) }; debug_assert!( status == crate::sys::Status::napi_ok, "Reference ref failed" ); Self { raw: self.raw, napi_ref: self.napi_ref, env: self.env, } } } /// ### Experimental feature /// /// Create a `SharedReference` from an existed `Reference`. pub struct SharedReference { raw: *mut S, owner: Reference, } unsafe impl Send for SharedReference {} unsafe impl Sync for SharedReference {} impl SharedReference { pub fn share_with Result>( self, f: F, ) -> Result> { let s = f(Box::leak(unsafe { Box::from_raw(self.raw) }))?; Ok(SharedReference { raw: Box::into_raw(Box::new(s)), owner: self.owner, }) } } impl Deref for SharedReference { type Target = S; fn deref(&self) -> &Self::Target { unsafe { Box::leak(Box::from_raw(self.raw)) } } } impl DerefMut for SharedReference { fn deref_mut(&mut self) -> &mut Self::Target { unsafe { Box::leak(Box::from_raw(self.raw)) } } } impl Clone for SharedReference { fn clone(&self) -> Self { let status = unsafe { crate::sys::napi_reference_ref(self.owner.env, self.owner.napi_ref, &mut 0) }; debug_assert!( status == crate::sys::Status::napi_ok, "Reference ref failed" ); Self { raw: self.raw, owner: self.owner.clone(), } } }