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))
|
||||
}
|
||||
});
|
||||
} else if rust_ty == "Reference" {
|
||||
} else if rust_ty == "Reference" || rust_ty == "WeakReference" {
|
||||
ts_ty = r#struct::TASK_STRUCTS.with(|t| {
|
||||
// Reference<T> => T
|
||||
if let Some(arg) = args.first() {
|
||||
|
|
|
@ -131,7 +131,7 @@ impl NapiFn {
|
|||
arguments: PathArguments::AngleBracketed(_),
|
||||
}) = path.path.segments.last()
|
||||
{
|
||||
if ident == "Reference" {
|
||||
if ident == "Reference" || ident == "WeakReference" {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::cell::Cell;
|
||||
use std::ffi::c_void;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::rc::Rc;
|
||||
use std::rc::{Rc, Weak};
|
||||
|
||||
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`
|
||||
pub fn share_with<S: 'static, F: FnOnce(&'static mut T) -> Result<S>>(
|
||||
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
|
||||
///
|
||||
/// Create a `SharedReference` from an existed `Reference`.
|
||||
|
|
|
@ -37,7 +37,6 @@ pub unsafe extern "C" fn raw_finalize_unchecked<T>(
|
|||
#[cfg(debug_assertions)]
|
||||
{
|
||||
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`
|
||||
// It always happened on exiting process
|
||||
// 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
|
||||
);
|
||||
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()) };
|
||||
finalize();
|
||||
|
|
|
@ -278,10 +278,12 @@ Generated by [AVA](https://avajs.dev).
|
|||
export type CSSRuleList = CssRuleList␊
|
||||
export class CssRuleList {␊
|
||||
getRules(): Array<string>␊
|
||||
get parentStyleSheet(): CSSStyleSheet␊
|
||||
get name(): string | null␊
|
||||
}␊
|
||||
export type CSSStyleSheet = CssStyleSheet␊
|
||||
export class CssStyleSheet {␊
|
||||
constructor(rules: Array<string>)␊
|
||||
constructor(name: string, rules: Array<string>)␊
|
||||
get rules(): CssRuleList␊
|
||||
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) => {
|
||||
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.deepEqual(sheet.rules.getRules(), rules)
|
||||
t.is(sheet.rules.parentStyleSheet, sheet)
|
||||
t.is(sheet.rules.name, 'test.css')
|
||||
const anotherStyleSheet = sheet.anotherCssStyleSheet()
|
||||
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 class CssRuleList {
|
||||
getRules(): Array<string>
|
||||
get parentStyleSheet(): CSSStyleSheet
|
||||
get name(): string | null
|
||||
}
|
||||
export type CSSStyleSheet = CssStyleSheet
|
||||
export class CssStyleSheet {
|
||||
constructor(rules: Array<string>)
|
||||
constructor(name: string, rules: Array<string>)
|
||||
get rules(): CssRuleList
|
||||
anotherCssStyleSheet(): AnotherCssStyleSheet
|
||||
}
|
||||
|
|
|
@ -64,6 +64,7 @@ struct OwnedStyleSheet {
|
|||
#[napi]
|
||||
pub struct CSSRuleList {
|
||||
owned: Rc<RefCell<OwnedStyleSheet>>,
|
||||
parent: WeakReference<CSSStyleSheet>,
|
||||
}
|
||||
|
||||
#[napi]
|
||||
|
@ -72,10 +73,26 @@ impl CSSRuleList {
|
|||
pub fn get_rules(&self) -> Vec<String> {
|
||||
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]
|
||||
pub struct CSSStyleSheet {
|
||||
name: String,
|
||||
inner: Rc<RefCell<OwnedStyleSheet>>,
|
||||
rules: Option<Reference<CSSRuleList>>,
|
||||
}
|
||||
|
@ -97,13 +114,21 @@ impl AnotherCSSStyleSheet {
|
|||
#[napi]
|
||||
impl CSSStyleSheet {
|
||||
#[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 }));
|
||||
Ok(CSSStyleSheet { inner, rules: None })
|
||||
Ok(CSSStyleSheet {
|
||||
name,
|
||||
inner,
|
||||
rules: None,
|
||||
})
|
||||
}
|
||||
|
||||
#[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 {
|
||||
return rules.clone(env);
|
||||
}
|
||||
|
@ -111,6 +136,7 @@ impl CSSStyleSheet {
|
|||
let rules = CSSRuleList::into_reference(
|
||||
CSSRuleList {
|
||||
owned: self.inner.clone(),
|
||||
parent: reference.downgrade(),
|
||||
},
|
||||
env,
|
||||
)?;
|
||||
|
|
Loading…
Reference in a new issue