2022-05-10 18:29:18 +09:00
|
|
|
use std::cell::Cell;
|
2022-03-21 17:36:06 +09:00
|
|
|
use std::ffi::c_void;
|
|
|
|
use std::ops::{Deref, DerefMut};
|
2022-04-02 16:19:53 +09:00
|
|
|
use std::rc::Rc;
|
2022-03-21 17:36:06 +09:00
|
|
|
|
2022-05-10 18:29:18 +09:00
|
|
|
use lazy_static::lazy_static;
|
|
|
|
|
|
|
|
use crate::{
|
|
|
|
bindgen_runtime::{PersistedSingleThreadHashMap, ToNapiValue},
|
|
|
|
check_status, Env, Error, Result, Status,
|
|
|
|
};
|
2022-03-21 17:36:06 +09:00
|
|
|
|
2022-04-02 16:19:53 +09:00
|
|
|
type RefInformation = (
|
|
|
|
*mut c_void,
|
|
|
|
crate::sys::napi_ref,
|
|
|
|
*const Cell<*mut dyn FnOnce()>,
|
|
|
|
);
|
2022-03-21 17:36:06 +09:00
|
|
|
|
2022-05-10 18:29:18 +09:00
|
|
|
lazy_static! {
|
|
|
|
pub(crate) static ref REFERENCE_MAP: PersistedSingleThreadHashMap<*mut c_void, RefInformation> =
|
|
|
|
Default::default();
|
2022-03-21 17:36:06 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
/// ### Experimental feature
|
|
|
|
///
|
|
|
|
/// Create a `reference` from `Class` instance.
|
|
|
|
/// Unref the `Reference` when the `Reference` is dropped.
|
2022-04-26 19:06:52 +09:00
|
|
|
pub struct Reference<T: 'static> {
|
2022-03-21 17:36:06 +09:00
|
|
|
raw: *mut T,
|
|
|
|
napi_ref: crate::sys::napi_ref,
|
2022-04-02 16:19:53 +09:00
|
|
|
env: *mut c_void,
|
|
|
|
finalize_callbacks: Rc<Cell<*mut dyn FnOnce()>>,
|
2022-03-21 17:36:06 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
unsafe impl<T: Send> Send for Reference<T> {}
|
|
|
|
unsafe impl<T: Sync> Sync for Reference<T> {}
|
|
|
|
|
|
|
|
impl<T> Drop for Reference<T> {
|
|
|
|
fn drop(&mut self) {
|
2022-05-03 09:27:18 +09:00
|
|
|
let rc_strong_count = Rc::strong_count(&self.finalize_callbacks);
|
|
|
|
let mut ref_count = 0;
|
|
|
|
// If Rc strong count == 1, then the referenced object is dropped on GC
|
|
|
|
// It would happen when the process is exiting
|
|
|
|
// In general, the `drop` of the `Reference` would happen first
|
|
|
|
if rc_strong_count > 1 {
|
|
|
|
let status = unsafe {
|
|
|
|
crate::sys::napi_reference_unref(
|
|
|
|
self.env as crate::sys::napi_env,
|
|
|
|
self.napi_ref,
|
|
|
|
&mut ref_count,
|
|
|
|
)
|
|
|
|
};
|
|
|
|
debug_assert!(
|
|
|
|
status == crate::sys::Status::napi_ok,
|
|
|
|
"Reference unref failed, status code: {}",
|
|
|
|
crate::Status::from(status)
|
|
|
|
);
|
2022-04-02 16:19:53 +09:00
|
|
|
};
|
2022-03-21 17:36:06 +09:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-26 19:06:52 +09:00
|
|
|
impl<T: 'static> Reference<T> {
|
2022-03-21 17:36:06 +09:00
|
|
|
#[doc(hidden)]
|
2022-04-02 16:19:53 +09:00
|
|
|
pub fn add_ref(t: *mut c_void, value: RefInformation) {
|
2022-05-10 18:29:18 +09:00
|
|
|
REFERENCE_MAP.borrow_mut(|map| {
|
|
|
|
map.insert(t, value);
|
2022-03-21 17:36:06 +09:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
#[doc(hidden)]
|
2022-04-02 16:19:53 +09:00
|
|
|
pub unsafe fn from_value_ptr(t: *mut c_void, env: crate::sys::napi_env) -> Result<Self> {
|
|
|
|
if let Some((wrapped_value, napi_ref, finalize_callbacks_ptr)) =
|
2022-05-10 18:29:18 +09:00
|
|
|
REFERENCE_MAP.borrow_mut(|map| map.get(&t).cloned())
|
2022-03-21 17:36:06 +09:00
|
|
|
{
|
|
|
|
check_status!(
|
|
|
|
unsafe { crate::sys::napi_reference_ref(env, napi_ref, &mut 0) },
|
|
|
|
"Failed to ref napi reference"
|
|
|
|
)?;
|
2022-04-02 16:19:53 +09:00
|
|
|
let finalize_callbacks_raw = unsafe { Rc::from_raw(finalize_callbacks_ptr) };
|
|
|
|
let finalize_callbacks = finalize_callbacks_raw.clone();
|
|
|
|
// Leak the raw finalize callbacks
|
|
|
|
Rc::into_raw(finalize_callbacks_raw);
|
2022-03-21 17:36:06 +09:00
|
|
|
Ok(Self {
|
|
|
|
raw: wrapped_value as *mut T,
|
|
|
|
napi_ref,
|
2022-04-02 16:19:53 +09:00
|
|
|
env: env as *mut c_void,
|
|
|
|
finalize_callbacks,
|
2022-03-21 17:36:06 +09:00
|
|
|
})
|
|
|
|
} else {
|
|
|
|
Err(Error::new(
|
|
|
|
Status::InvalidArg,
|
|
|
|
format!("Class for Type {:?} not found", t),
|
|
|
|
))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-26 19:06:52 +09:00
|
|
|
impl<T: 'static> ToNapiValue for Reference<T> {
|
|
|
|
unsafe fn to_napi_value(env: crate::sys::napi_env, val: Self) -> Result<crate::sys::napi_value> {
|
|
|
|
let mut result = std::ptr::null_mut();
|
|
|
|
check_status!(
|
|
|
|
unsafe { crate::sys::napi_get_reference_value(env, val.napi_ref, &mut result) },
|
|
|
|
"Failed to get reference value"
|
|
|
|
)?;
|
|
|
|
Ok(result)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-21 17:36:06 +09:00
|
|
|
impl<T: 'static> Reference<T> {
|
2022-04-02 16:19:53 +09:00
|
|
|
pub fn clone(&self, env: Env) -> Result<Self> {
|
|
|
|
let mut ref_count = 0;
|
|
|
|
check_status!(
|
|
|
|
unsafe { crate::sys::napi_reference_ref(env.0, self.napi_ref, &mut ref_count) },
|
|
|
|
"Failed to ref napi reference"
|
|
|
|
)?;
|
|
|
|
Ok(Self {
|
|
|
|
raw: self.raw,
|
|
|
|
napi_ref: self.napi_ref,
|
|
|
|
env: env.0 as *mut c_void,
|
|
|
|
finalize_callbacks: self.finalize_callbacks.clone(),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Safety to share because caller can provide `Env`
|
|
|
|
pub fn share_with<S: 'static, F: FnOnce(&'static mut T) -> Result<S>>(
|
2022-03-21 17:36:06 +09:00
|
|
|
self,
|
2022-04-02 16:19:53 +09:00
|
|
|
#[allow(unused_variables)] env: Env,
|
2022-03-21 17:36:06 +09:00
|
|
|
f: F,
|
|
|
|
) -> Result<SharedReference<T, S>> {
|
|
|
|
let s = f(Box::leak(unsafe { Box::from_raw(self.raw) }))?;
|
2022-04-02 16:19:53 +09:00
|
|
|
let s_ptr = Box::into_raw(Box::new(s));
|
|
|
|
let prev_drop_fn = unsafe { Box::from_raw(self.finalize_callbacks.get()) };
|
|
|
|
let drop_fn = Box::new(move || {
|
|
|
|
unsafe { Box::from_raw(s_ptr) };
|
|
|
|
prev_drop_fn();
|
|
|
|
});
|
|
|
|
self.finalize_callbacks.set(Box::into_raw(drop_fn));
|
2022-03-21 17:36:06 +09:00
|
|
|
Ok(SharedReference {
|
2022-04-02 16:19:53 +09:00
|
|
|
raw: s_ptr,
|
2022-03-21 17:36:06 +09:00
|
|
|
owner: self,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-26 19:06:52 +09:00
|
|
|
impl<T: 'static> Deref for Reference<T> {
|
2022-03-21 17:36:06 +09:00
|
|
|
type Target = T;
|
|
|
|
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
|
|
unsafe { Box::leak(Box::from_raw(self.raw)) }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-26 19:06:52 +09:00
|
|
|
impl<T: 'static> DerefMut for Reference<T> {
|
2022-03-21 17:36:06 +09:00
|
|
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
|
|
unsafe { Box::leak(Box::from_raw(self.raw)) }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// ### Experimental feature
|
|
|
|
///
|
|
|
|
/// Create a `SharedReference` from an existed `Reference`.
|
2022-04-26 19:06:52 +09:00
|
|
|
pub struct SharedReference<T: 'static, S: 'static> {
|
2022-03-21 17:36:06 +09:00
|
|
|
raw: *mut S,
|
|
|
|
owner: Reference<T>,
|
|
|
|
}
|
|
|
|
|
|
|
|
unsafe impl<T: Send, S: Send> Send for SharedReference<T, S> {}
|
|
|
|
unsafe impl<T: Sync, S: Sync> Sync for SharedReference<T, S> {}
|
|
|
|
|
2022-04-02 16:19:53 +09:00
|
|
|
impl<T: 'static, S: 'static> SharedReference<T, S> {
|
|
|
|
pub fn clone(&self, env: Env) -> Result<Self> {
|
|
|
|
Ok(SharedReference {
|
|
|
|
raw: self.raw,
|
|
|
|
owner: self.owner.clone(env)?,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2022-05-06 18:40:46 +09:00
|
|
|
pub fn clone_owner(&self, env: Env) -> Result<Reference<T>> {
|
|
|
|
self.owner.clone(env)
|
|
|
|
}
|
|
|
|
|
2022-04-02 16:19:53 +09:00
|
|
|
/// Safety to share because caller can provide `Env`
|
|
|
|
pub fn share_with<U: 'static, F: FnOnce(&'static mut S) -> Result<U>>(
|
2022-03-21 17:36:06 +09:00
|
|
|
self,
|
2022-04-02 16:19:53 +09:00
|
|
|
#[allow(unused_variables)] env: Env,
|
2022-03-21 17:36:06 +09:00
|
|
|
f: F,
|
|
|
|
) -> Result<SharedReference<T, U>> {
|
|
|
|
let s = f(Box::leak(unsafe { Box::from_raw(self.raw) }))?;
|
2022-04-02 16:19:53 +09:00
|
|
|
let raw = Box::into_raw(Box::new(s));
|
|
|
|
let prev_drop_fn = unsafe { Box::from_raw(self.owner.finalize_callbacks.get()) };
|
|
|
|
let drop_fn = Box::new(move || {
|
|
|
|
unsafe { Box::from_raw(raw) };
|
|
|
|
prev_drop_fn();
|
|
|
|
});
|
|
|
|
self.owner.finalize_callbacks.set(Box::into_raw(drop_fn));
|
2022-03-21 17:36:06 +09:00
|
|
|
Ok(SharedReference {
|
2022-04-02 16:19:53 +09:00
|
|
|
raw,
|
2022-03-21 17:36:06 +09:00
|
|
|
owner: self.owner,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-26 19:06:52 +09:00
|
|
|
impl<T: 'static, S: 'static> ToNapiValue for SharedReference<T, S> {
|
|
|
|
unsafe fn to_napi_value(env: crate::sys::napi_env, val: Self) -> Result<crate::sys::napi_value> {
|
|
|
|
let mut result = std::ptr::null_mut();
|
|
|
|
check_status!(
|
|
|
|
unsafe { crate::sys::napi_get_reference_value(env, val.owner.napi_ref, &mut result) },
|
|
|
|
"Failed to get reference value"
|
|
|
|
)?;
|
|
|
|
Ok(result)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: 'static, S: 'static> Deref for SharedReference<T, S> {
|
2022-03-21 17:36:06 +09:00
|
|
|
type Target = S;
|
|
|
|
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
|
|
unsafe { Box::leak(Box::from_raw(self.raw)) }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-26 19:06:52 +09:00
|
|
|
impl<T: 'static, S: 'static> DerefMut for SharedReference<T, S> {
|
2022-03-21 17:36:06 +09:00
|
|
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
|
|
unsafe { Box::leak(Box::from_raw(self.raw)) }
|
|
|
|
}
|
|
|
|
}
|