feat(napi): add support for weak references
This commit is contained in:
parent
5ecf16e5ad
commit
27402aee81
9 changed files with 96 additions and 15 deletions
|
@ -280,7 +280,7 @@ pub fn ty_to_ts_type(ty: &Type, is_return_ty: bool, is_struct_field: bool) -> (S
|
||||||
Some(("Promise<unknown>".to_owned(), false))
|
Some(("Promise<unknown>".to_owned(), false))
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else if rust_ty == "Reference" {
|
} else if rust_ty == "Reference" || rust_ty == "WeakReference" {
|
||||||
ts_ty = r#struct::TASK_STRUCTS.with(|t| {
|
ts_ty = r#struct::TASK_STRUCTS.with(|t| {
|
||||||
// Reference<T> => T
|
// Reference<T> => T
|
||||||
if let Some(arg) = args.first() {
|
if let Some(arg) = args.first() {
|
||||||
|
|
|
@ -131,7 +131,7 @@ impl NapiFn {
|
||||||
arguments: PathArguments::AngleBracketed(_),
|
arguments: PathArguments::AngleBracketed(_),
|
||||||
}) = path.path.segments.last()
|
}) = path.path.segments.last()
|
||||||
{
|
{
|
||||||
if ident == "Reference" {
|
if ident == "Reference" || ident == "WeakReference" {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::ffi::c_void;
|
use std::ffi::c_void;
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
use std::rc::Rc;
|
use std::rc::{Rc, Weak};
|
||||||
|
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
|
|
||||||
|
@ -121,6 +121,14 @@ impl<T: 'static> Reference<T> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn downgrade(&self) -> WeakReference<T> {
|
||||||
|
WeakReference {
|
||||||
|
raw: self.raw,
|
||||||
|
napi_ref: self.napi_ref,
|
||||||
|
finalize_callbacks: Rc::downgrade(&self.finalize_callbacks),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Safety to share because caller can provide `Env`
|
/// Safety to share because caller can provide `Env`
|
||||||
pub fn share_with<S: 'static, F: FnOnce(&'static mut T) -> Result<S>>(
|
pub fn share_with<S: 'static, F: FnOnce(&'static mut T) -> Result<S>>(
|
||||||
self,
|
self,
|
||||||
|
@ -156,6 +164,53 @@ impl<T: 'static> DerefMut for Reference<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct WeakReference<T: 'static> {
|
||||||
|
raw: *mut T,
|
||||||
|
napi_ref: crate::sys::napi_ref,
|
||||||
|
finalize_callbacks: Weak<Cell<*mut dyn FnOnce()>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Clone for WeakReference<T> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self {
|
||||||
|
raw: self.raw,
|
||||||
|
napi_ref: self.napi_ref,
|
||||||
|
finalize_callbacks: self.finalize_callbacks.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: 'static> ToNapiValue for WeakReference<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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: 'static> WeakReference<T> {
|
||||||
|
pub fn upgrade(&self, env: Env) -> Result<Option<Reference<T>>> {
|
||||||
|
if let Some(finalize_callbacks) = self.finalize_callbacks.upgrade() {
|
||||||
|
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(Some(Reference {
|
||||||
|
raw: self.raw,
|
||||||
|
napi_ref: self.napi_ref,
|
||||||
|
env: env.0 as *mut c_void,
|
||||||
|
finalize_callbacks,
|
||||||
|
}))
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// ### Experimental feature
|
/// ### Experimental feature
|
||||||
///
|
///
|
||||||
/// Create a `SharedReference` from an existed `Reference`.
|
/// Create a `SharedReference` from an existed `Reference`.
|
||||||
|
|
|
@ -37,7 +37,6 @@ pub unsafe extern "C" fn raw_finalize_unchecked<T>(
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
{
|
{
|
||||||
let rc_strong_count = Rc::strong_count(&finalize_callbacks_rc);
|
let rc_strong_count = Rc::strong_count(&finalize_callbacks_rc);
|
||||||
let rc_weak_count = Rc::weak_count(&finalize_callbacks_rc);
|
|
||||||
// If `Rc` strong count is 2, it means the finalize of referenced `Object` is called before the `fn drop` of the `Reference`
|
// If `Rc` strong count is 2, it means the finalize of referenced `Object` is called before the `fn drop` of the `Reference`
|
||||||
// It always happened on exiting process
|
// It always happened on exiting process
|
||||||
// In general, the `fn drop` would happen first
|
// In general, the `fn drop` would happen first
|
||||||
|
@ -46,11 +45,6 @@ pub unsafe extern "C" fn raw_finalize_unchecked<T>(
|
||||||
"Rc strong count is: {}, it should be 1 or 2",
|
"Rc strong count is: {}, it should be 1 or 2",
|
||||||
rc_strong_count
|
rc_strong_count
|
||||||
);
|
);
|
||||||
assert!(
|
|
||||||
rc_weak_count == 0,
|
|
||||||
"Rc weak count is: {}, it should be 0",
|
|
||||||
rc_weak_count
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
let finalize = unsafe { Box::from_raw(finalize_callbacks_rc.get()) };
|
let finalize = unsafe { Box::from_raw(finalize_callbacks_rc.get()) };
|
||||||
finalize();
|
finalize();
|
||||||
|
|
|
@ -278,10 +278,12 @@ Generated by [AVA](https://avajs.dev).
|
||||||
export type CSSRuleList = CssRuleList␊
|
export type CSSRuleList = CssRuleList␊
|
||||||
export class CssRuleList {␊
|
export class CssRuleList {␊
|
||||||
getRules(): Array<string>␊
|
getRules(): Array<string>␊
|
||||||
|
get parentStyleSheet(): CSSStyleSheet␊
|
||||||
|
get name(): string | null␊
|
||||||
}␊
|
}␊
|
||||||
export type CSSStyleSheet = CssStyleSheet␊
|
export type CSSStyleSheet = CssStyleSheet␊
|
||||||
export class CssStyleSheet {␊
|
export class CssStyleSheet {␊
|
||||||
constructor(rules: Array<string>)␊
|
constructor(name: string, rules: Array<string>)␊
|
||||||
get rules(): CssRuleList␊
|
get rules(): CssRuleList␊
|
||||||
anotherCssStyleSheet(): AnotherCssStyleSheet␊
|
anotherCssStyleSheet(): AnotherCssStyleSheet␊
|
||||||
}␊
|
}␊
|
||||||
|
|
Binary file not shown.
|
@ -202,9 +202,11 @@ test('should be able to create object reference and shared reference', (t) => {
|
||||||
|
|
||||||
test('should be able to into_reference', (t) => {
|
test('should be able to into_reference', (t) => {
|
||||||
const rules = ['body: { color: red }', 'div: { color: blue }']
|
const rules = ['body: { color: red }', 'div: { color: blue }']
|
||||||
const sheet = new CssStyleSheet(rules)
|
const sheet = new CssStyleSheet('test.css', rules)
|
||||||
t.is(sheet.rules, sheet.rules)
|
t.is(sheet.rules, sheet.rules)
|
||||||
t.deepEqual(sheet.rules.getRules(), rules)
|
t.deepEqual(sheet.rules.getRules(), rules)
|
||||||
|
t.is(sheet.rules.parentStyleSheet, sheet)
|
||||||
|
t.is(sheet.rules.name, 'test.css')
|
||||||
const anotherStyleSheet = sheet.anotherCssStyleSheet()
|
const anotherStyleSheet = sheet.anotherCssStyleSheet()
|
||||||
t.is(anotherStyleSheet.rules, sheet.rules)
|
t.is(anotherStyleSheet.rules, sheet.rules)
|
||||||
})
|
})
|
||||||
|
|
4
examples/napi/index.d.ts
vendored
4
examples/napi/index.d.ts
vendored
|
@ -268,10 +268,12 @@ export class JsRemote {
|
||||||
export type CSSRuleList = CssRuleList
|
export type CSSRuleList = CssRuleList
|
||||||
export class CssRuleList {
|
export class CssRuleList {
|
||||||
getRules(): Array<string>
|
getRules(): Array<string>
|
||||||
|
get parentStyleSheet(): CSSStyleSheet
|
||||||
|
get name(): string | null
|
||||||
}
|
}
|
||||||
export type CSSStyleSheet = CssStyleSheet
|
export type CSSStyleSheet = CssStyleSheet
|
||||||
export class CssStyleSheet {
|
export class CssStyleSheet {
|
||||||
constructor(rules: Array<string>)
|
constructor(name: string, rules: Array<string>)
|
||||||
get rules(): CssRuleList
|
get rules(): CssRuleList
|
||||||
anotherCssStyleSheet(): AnotherCssStyleSheet
|
anotherCssStyleSheet(): AnotherCssStyleSheet
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,6 +64,7 @@ struct OwnedStyleSheet {
|
||||||
#[napi]
|
#[napi]
|
||||||
pub struct CSSRuleList {
|
pub struct CSSRuleList {
|
||||||
owned: Rc<RefCell<OwnedStyleSheet>>,
|
owned: Rc<RefCell<OwnedStyleSheet>>,
|
||||||
|
parent: WeakReference<CSSStyleSheet>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[napi]
|
#[napi]
|
||||||
|
@ -72,10 +73,26 @@ impl CSSRuleList {
|
||||||
pub fn get_rules(&self) -> Vec<String> {
|
pub fn get_rules(&self) -> Vec<String> {
|
||||||
self.owned.borrow().rules.to_vec()
|
self.owned.borrow().rules.to_vec()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[napi(getter)]
|
||||||
|
pub fn parent_style_sheet(&self) -> WeakReference<CSSStyleSheet> {
|
||||||
|
self.parent.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[napi(getter)]
|
||||||
|
pub fn name(&self, env: Env) -> Result<Option<String>> {
|
||||||
|
Ok(
|
||||||
|
self
|
||||||
|
.parent
|
||||||
|
.upgrade(env)?
|
||||||
|
.map(|stylesheet| stylesheet.name.clone()),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[napi]
|
#[napi]
|
||||||
pub struct CSSStyleSheet {
|
pub struct CSSStyleSheet {
|
||||||
|
name: String,
|
||||||
inner: Rc<RefCell<OwnedStyleSheet>>,
|
inner: Rc<RefCell<OwnedStyleSheet>>,
|
||||||
rules: Option<Reference<CSSRuleList>>,
|
rules: Option<Reference<CSSRuleList>>,
|
||||||
}
|
}
|
||||||
|
@ -97,13 +114,21 @@ impl AnotherCSSStyleSheet {
|
||||||
#[napi]
|
#[napi]
|
||||||
impl CSSStyleSheet {
|
impl CSSStyleSheet {
|
||||||
#[napi(constructor)]
|
#[napi(constructor)]
|
||||||
pub fn new(rules: Vec<String>) -> Result<Self> {
|
pub fn new(name: String, rules: Vec<String>) -> Result<Self> {
|
||||||
let inner = Rc::new(RefCell::new(OwnedStyleSheet { rules }));
|
let inner = Rc::new(RefCell::new(OwnedStyleSheet { rules }));
|
||||||
Ok(CSSStyleSheet { inner, rules: None })
|
Ok(CSSStyleSheet {
|
||||||
|
name,
|
||||||
|
inner,
|
||||||
|
rules: None,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[napi(getter)]
|
#[napi(getter)]
|
||||||
pub fn rules(&mut self, env: Env) -> Result<Reference<CSSRuleList>> {
|
pub fn rules(
|
||||||
|
&mut self,
|
||||||
|
env: Env,
|
||||||
|
reference: Reference<CSSStyleSheet>,
|
||||||
|
) -> Result<Reference<CSSRuleList>> {
|
||||||
if let Some(rules) = &self.rules {
|
if let Some(rules) = &self.rules {
|
||||||
return rules.clone(env);
|
return rules.clone(env);
|
||||||
}
|
}
|
||||||
|
@ -111,6 +136,7 @@ impl CSSStyleSheet {
|
||||||
let rules = CSSRuleList::into_reference(
|
let rules = CSSRuleList::into_reference(
|
||||||
CSSRuleList {
|
CSSRuleList {
|
||||||
owned: self.inner.clone(),
|
owned: self.inner.clone(),
|
||||||
|
parent: reference.downgrade(),
|
||||||
},
|
},
|
||||||
env,
|
env,
|
||||||
)?;
|
)?;
|
||||||
|
|
Loading…
Reference in a new issue