From 878b843f29b89f0cd8b59827665e1343b9682f32 Mon Sep 17 00:00:00 2001 From: LongYinan Date: Tue, 26 Apr 2022 18:06:52 +0800 Subject: [PATCH] feat(napi): support return Reference on class instance --- crates/backend/src/codegen/struct.rs | 97 +++++++++++------- crates/backend/src/typegen.rs | 9 ++ .../bindgen_runtime/js_values/value_ref.rs | 38 +++++-- examples/napi/__test__/typegen.spec.ts.md | 9 ++ examples/napi/__test__/typegen.spec.ts.snap | Bin 2937 -> 2995 bytes examples/napi/__test__/values.spec.ts | 8 ++ examples/napi/index.d.ts | 9 ++ examples/napi/src/reference.rs | 45 ++++++++ 8 files changed, 171 insertions(+), 44 deletions(-) diff --git a/crates/backend/src/codegen/struct.rs b/crates/backend/src/codegen/struct.rs index 36046126..9fd954d7 100644 --- a/crates/backend/src/codegen/struct.rs +++ b/crates/backend/src/codegen/struct.rs @@ -216,54 +216,79 @@ impl NapiStruct { fn gen_to_napi_value_ctor_impl_for_non_default_constructor_struct(&self) -> TokenStream { let name = &self.name; - let js_name_str = format!("{}\0", &self.js_name); + let js_name_raw = &self.js_name; + let js_name_str = format!("{}\0", js_name_raw); quote! { impl napi::bindgen_prelude::ToNapiValue for #name { unsafe fn to_napi_value( - env: napi::sys::napi_env, val: #name + env: napi::sys::napi_env, + val: #name ) -> napi::Result { if let Some(ctor_ref) = napi::bindgen_prelude::get_class_constructor(#js_name_str) { - let mut ctor = std::ptr::null_mut(); - - napi::check_status!( - napi::sys::napi_get_reference_value(env, ctor_ref, &mut ctor), - "Failed to get constructor of class `{}`", - #js_name_str - )?; - - let mut result = std::ptr::null_mut(); - napi::bindgen_prelude::___CALL_FROM_FACTORY.with(|inner| inner.store(true, std::sync::atomic::Ordering::Relaxed)); - napi::check_status!( - napi::sys::napi_new_instance(env, ctor, 0, std::ptr::null_mut(), &mut result), - "Failed to construct class `{}`", - #js_name_str - )?; let wrapped_value = Box::into_raw(Box::new(val)) as *mut std::ffi::c_void; - let mut object_ref = std::ptr::null_mut(); - let initial_finalize: Box = Box::new(|| {}); - let finalize_callbacks_ptr = std::rc::Rc::into_raw(std::rc::Rc::new(std::cell::Cell::new(Box::into_raw(initial_finalize)))); - napi::check_status!( - napi::sys::napi_wrap( - env, - result, - wrapped_value, - Some(napi::bindgen_prelude::raw_finalize_unchecked::<#name>), - std::ptr::null_mut(), - &mut object_ref, - ), - "Failed to wrap native object of class `{}`", - #js_name_str - )?; - napi::bindgen_prelude::Reference::<#name>::add_ref(wrapped_value, (wrapped_value, object_ref, finalize_callbacks_ptr)); - napi::bindgen_prelude::___CALL_FROM_FACTORY.with(|inner| inner.store(false, std::sync::atomic::Ordering::Relaxed)); - Ok(result) + #name::new_instance(env, wrapped_value, ctor_ref) } else { Err(napi::bindgen_prelude::Error::new( - napi::bindgen_prelude::Status::InvalidArg, format!("Failed to get constructor of class `{}`", #js_name_str)) + napi::bindgen_prelude::Status::InvalidArg, format!("Failed to get constructor of class `{}`", #js_name_raw)) ) } } } + + impl #name { + pub fn into_reference(val: #name, env: napi::Env) -> napi::Result> { + if let Some(ctor_ref) = napi::bindgen_prelude::get_class_constructor(#js_name_str) { + unsafe { + let wrapped_value = Box::into_raw(Box::new(val)) as *mut std::ffi::c_void; + #name::new_instance(env.raw(), wrapped_value, ctor_ref)?; + napi::bindgen_prelude::Reference::<#name>::from_value_ptr(wrapped_value, env.raw()) + } + } else { + Err(napi::bindgen_prelude::Error::new( + napi::bindgen_prelude::Status::InvalidArg, format!("Failed to get constructor of class `{}`", #js_name_raw)) + ) + } + } + + unsafe fn new_instance( + env: napi::sys::napi_env, + wrapped_value: *mut std::ffi::c_void, + ctor_ref: napi::sys::napi_ref, + ) -> napi::Result { + let mut ctor = std::ptr::null_mut(); + napi::check_status!( + napi::sys::napi_get_reference_value(env, ctor_ref, &mut ctor), + "Failed to get constructor of class `{}`", + #js_name_raw + )?; + + let mut result = std::ptr::null_mut(); + napi::bindgen_prelude::___CALL_FROM_FACTORY.with(|inner| inner.store(true, std::sync::atomic::Ordering::Relaxed)); + napi::check_status!( + napi::sys::napi_new_instance(env, ctor, 0, std::ptr::null_mut(), &mut result), + "Failed to construct class `{}`", + #js_name_raw + )?; + let mut object_ref = std::ptr::null_mut(); + let initial_finalize: Box = Box::new(|| {}); + let finalize_callbacks_ptr = std::rc::Rc::into_raw(std::rc::Rc::new(std::cell::Cell::new(Box::into_raw(initial_finalize)))); + napi::check_status!( + napi::sys::napi_wrap( + env, + result, + wrapped_value, + Some(napi::bindgen_prelude::raw_finalize_unchecked::<#name>), + std::ptr::null_mut(), + &mut object_ref, + ), + "Failed to wrap native object of class `{}`", + #js_name_raw + )?; + napi::bindgen_prelude::Reference::<#name>::add_ref(wrapped_value, (wrapped_value, object_ref, finalize_callbacks_ptr)); + napi::bindgen_prelude::___CALL_FROM_FACTORY.with(|inner| inner.store(false, std::sync::atomic::Ordering::Relaxed)); + Ok(result) + } + } } } diff --git a/crates/backend/src/typegen.rs b/crates/backend/src/typegen.rs index 916fbd37..ba54b16d 100644 --- a/crates/backend/src/typegen.rs +++ b/crates/backend/src/typegen.rs @@ -278,6 +278,15 @@ pub fn ty_to_ts_type(ty: &Type, is_return_ty: bool, is_struct_field: bool) -> (S Some(("Promise".to_owned(), false)) } }); + } else if rust_ty == "Reference" { + ts_ty = r#struct::TASK_STRUCTS.with(|t| { + let (output_type, _) = args.first().unwrap().to_owned(); + if let Some(o) = t.borrow().get(&output_type) { + Some((o.to_owned(), false)) + } else { + Some((output_type, false)) + } + }); } else if let Some(&known_ty) = KNOWN_TYPES.get(rust_ty.as_str()) { if known_ty.contains("{}") { ts_ty = Some(( diff --git a/crates/napi/src/bindgen_runtime/js_values/value_ref.rs b/crates/napi/src/bindgen_runtime/js_values/value_ref.rs index 21647eb4..6443d810 100644 --- a/crates/napi/src/bindgen_runtime/js_values/value_ref.rs +++ b/crates/napi/src/bindgen_runtime/js_values/value_ref.rs @@ -4,7 +4,7 @@ use std::ffi::c_void; use std::ops::{Deref, DerefMut}; use std::rc::Rc; -use crate::{check_status, Env, Error, Result, Status}; +use crate::{bindgen_runtime::ToNapiValue, check_status, Env, Error, Result, Status}; type RefInformation = ( *mut c_void, @@ -20,7 +20,7 @@ thread_local! { /// /// Create a `reference` from `Class` instance. /// Unref the `Reference` when the `Reference` is dropped. -pub struct Reference { +pub struct Reference { raw: *mut T, napi_ref: crate::sys::napi_ref, env: *mut c_void, @@ -42,7 +42,7 @@ impl Drop for Reference { } } -impl Reference { +impl Reference { #[doc(hidden)] pub fn add_ref(t: *mut c_void, value: RefInformation) { REFERENCE_MAP.with(|map| { @@ -78,6 +78,17 @@ impl Reference { } } +impl ToNapiValue for Reference { + unsafe fn to_napi_value(env: crate::sys::napi_env, val: Self) -> Result { + 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 Reference { pub fn clone(&self, env: Env) -> Result { let mut ref_count = 0; @@ -114,7 +125,7 @@ impl Reference { } } -impl Deref for Reference { +impl Deref for Reference { type Target = T; fn deref(&self) -> &Self::Target { @@ -122,7 +133,7 @@ impl Deref for Reference { } } -impl DerefMut for Reference { +impl DerefMut for Reference { fn deref_mut(&mut self) -> &mut Self::Target { unsafe { Box::leak(Box::from_raw(self.raw)) } } @@ -131,7 +142,7 @@ impl DerefMut for Reference { /// ### Experimental feature /// /// Create a `SharedReference` from an existed `Reference`. -pub struct SharedReference { +pub struct SharedReference { raw: *mut S, owner: Reference, } @@ -168,7 +179,18 @@ impl SharedReference { } } -impl Deref for SharedReference { +impl ToNapiValue for SharedReference { + unsafe fn to_napi_value(env: crate::sys::napi_env, val: Self) -> Result { + 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 Deref for SharedReference { type Target = S; fn deref(&self) -> &Self::Target { @@ -176,7 +198,7 @@ impl Deref for SharedReference { } } -impl DerefMut for SharedReference { +impl DerefMut for SharedReference { fn deref_mut(&mut self) -> &mut Self::Target { unsafe { Box::leak(Box::from_raw(self.raw)) } } diff --git a/examples/napi/__test__/typegen.spec.ts.md b/examples/napi/__test__/typegen.spec.ts.md index a1ef7ede..0eeafa58 100644 --- a/examples/napi/__test__/typegen.spec.ts.md +++ b/examples/napi/__test__/typegen.spec.ts.md @@ -271,6 +271,15 @@ Generated by [AVA](https://avajs.dev). export class JsRemote {␊ name(): string␊ }␊ + export type CSSRuleList = CssRuleList␊ + export class CssRuleList {␊ + getRules(): Array␊ + }␊ + export type CSSStyleSheet = CssStyleSheet␊ + export class CssStyleSheet {␊ + constructor(rules: Array)␊ + get rules(): CssRuleList␊ + }␊ export namespace xxh3 {␊ export const ALIGNMENT: number␊ export function xxh3_64(input: Buffer): bigint␊ diff --git a/examples/napi/__test__/typegen.spec.ts.snap b/examples/napi/__test__/typegen.spec.ts.snap index 2fedede7bbd1cd05d7f3c76d4b9c06f82f15c2ff..4c495ff76970564aa522fbec63942d450bd8765a 100644 GIT binary patch literal 2995 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 literal 2937 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 diff --git a/examples/napi/__test__/values.spec.ts b/examples/napi/__test__/values.spec.ts index cac38f37..fcab599d 100644 --- a/examples/napi/__test__/values.spec.ts +++ b/examples/napi/__test__/values.spec.ts @@ -90,6 +90,7 @@ import { chronoDateAdd1Minute, bufferPassThrough, JsRepo, + CssStyleSheet, asyncReduceBuffer, callbackReturnPromise, } from '../' @@ -199,6 +200,13 @@ test('should be able to create object reference and shared reference', (t) => { t.is(repo.remote().name(), 'origin') }) +test('should be able to into_reference', (t) => { + const rules = ['body: { color: red }', 'div: { color: blue }'] + const sheet = new CssStyleSheet(rules) + t.is(sheet.rules, sheet.rules) + t.deepEqual(sheet.rules.getRules(), rules) +}) + test('callback', (t) => { getCwd((cwd) => { t.is(cwd, process.cwd()) diff --git a/examples/napi/index.d.ts b/examples/napi/index.d.ts index 12fdd1a9..3269086e 100644 --- a/examples/napi/index.d.ts +++ b/examples/napi/index.d.ts @@ -261,6 +261,15 @@ export class JsRepo { export class JsRemote { name(): string } +export type CSSRuleList = CssRuleList +export class CssRuleList { + getRules(): Array +} +export type CSSStyleSheet = CssStyleSheet +export class CssStyleSheet { + constructor(rules: Array) + get rules(): CssRuleList +} export namespace xxh3 { export const ALIGNMENT: number export function xxh3_64(input: Buffer): bigint diff --git a/examples/napi/src/reference.rs b/examples/napi/src/reference.rs index 887ecbce..ace4f229 100644 --- a/examples/napi/src/reference.rs +++ b/examples/napi/src/reference.rs @@ -1,3 +1,5 @@ +use std::{cell::RefCell, rc::Rc}; + use napi::bindgen_prelude::*; pub struct Repository { @@ -54,3 +56,46 @@ impl JsRemote { self.inner.name() } } + +struct OwnedStyleSheet { + rules: Vec, +} + +#[napi] +pub struct CSSRuleList { + owned: Rc>, +} + +#[napi] +impl CSSRuleList { + #[napi] + pub fn get_rules(&self) -> Vec { + self.owned.borrow().rules.to_vec() + } +} + +#[napi] +pub struct CSSStyleSheet { + inner: Rc>, + rules: Reference, +} + +#[napi] +impl CSSStyleSheet { + #[napi(constructor)] + pub fn new(env: Env, rules: Vec) -> Result { + let inner = Rc::new(RefCell::new(OwnedStyleSheet { rules })); + let rules = CSSRuleList::into_reference( + CSSRuleList { + owned: inner.clone(), + }, + env, + )?; + Ok(CSSStyleSheet { inner, rules }) + } + + #[napi(getter)] + pub fn rules(&self, env: Env) -> Result> { + self.rules.clone(env) + } +}