From 2385b52a725f26231cf640db1f2317429d866681 Mon Sep 17 00:00:00 2001 From: LongYinan Date: Wed, 17 Aug 2022 13:24:40 +0800 Subject: [PATCH] feat(napi): allow implement custom finalize logic for Class --- crates/backend/src/ast.rs | 1 + crates/backend/src/codegen/struct.rs | 15 ++++++ crates/macro/src/parser/attrs.rs | 1 + crates/macro/src/parser/mod.rs | 47 ++++++++++++++++-- .../napi/src/bindgen_runtime/callback_info.rs | 28 ++++++++--- crates/napi/src/bindgen_runtime/mod.rs | 17 +++++-- examples/napi/__test__/typegen.spec.ts.md | 3 ++ examples/napi/__test__/typegen.spec.ts.snap | Bin 3488 -> 3515 bytes examples/napi/__test__/values.spec.ts | 5 ++ examples/napi/index.d.ts | 3 ++ examples/napi/src/class.rs | 31 +++++++++++- 11 files changed, 136 insertions(+), 15 deletions(-) diff --git a/crates/backend/src/ast.rs b/crates/backend/src/ast.rs index f82d7e3e..64677f82 100644 --- a/crates/backend/src/ast.rs +++ b/crates/backend/src/ast.rs @@ -81,6 +81,7 @@ pub struct NapiStruct { pub js_mod: Option, pub comments: Vec, pub implement_iterator: bool, + pub use_custom_finalize: bool, } #[derive(Debug, Clone, PartialEq)] diff --git a/crates/backend/src/codegen/struct.rs b/crates/backend/src/codegen/struct.rs index 38a82fe6..411825db 100644 --- a/crates/backend/src/codegen/struct.rs +++ b/crates/backend/src/codegen/struct.rs @@ -278,6 +278,11 @@ impl NapiStruct { let js_name_raw = &self.js_name; let js_name_str = format!("{}\0", js_name_raw); let iterator_implementation = self.gen_iterator_property(name); + let finalize_trait = if self.use_custom_finalize { + quote! {} + } else { + quote! { impl napi::bindgen_prelude::ObjectFinalize for #name {} } + }; quote! { impl napi::bindgen_prelude::ToNapiValue for #name { unsafe fn to_napi_value( @@ -297,6 +302,8 @@ impl NapiStruct { } } + #finalize_trait + 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) { @@ -420,6 +427,12 @@ impl NapiStruct { } }; + let finalize_trait = if self.use_custom_finalize { + quote! {} + } else { + quote! { impl napi::bindgen_prelude::ObjectFinalize for #name {} } + }; + quote! { impl napi::bindgen_prelude::ToNapiValue for #name { unsafe fn to_napi_value( @@ -453,6 +466,8 @@ impl NapiStruct { } } } + + #finalize_trait } } diff --git a/crates/macro/src/parser/attrs.rs b/crates/macro/src/parser/attrs.rs index 3b3b0418..f7e2a7e0 100644 --- a/crates/macro/src/parser/attrs.rs +++ b/crates/macro/src/parser/attrs.rs @@ -55,6 +55,7 @@ macro_rules! attrgen { (strict, Strict(Span)), (return_if_invalid, ReturnIfInvalid(Span)), (object, Object(Span)), + (custom_finalize, CustomFinalize(Span)), (namespace, Namespace(Span, String, Span)), (iterator, Iterator(Span)), (ts_args_type, TsArgsType(Span, String, Span)), diff --git a/crates/macro/src/parser/mod.rs b/crates/macro/src/parser/mod.rs index 5450ff1b..ec91abfd 100644 --- a/crates/macro/src/parser/mod.rs +++ b/crates/macro/src/parser/mod.rs @@ -741,22 +741,39 @@ impl ParseNapi for syn::ItemStruct { "#[napi] can't be applied to a struct with #[napi(ts_args_type)], #[napi(ts_return_type)], #[napi(skip_typescript)] or #[napi(ts_type)]" ); } + if opts.return_if_invalid().is_some() { + bail_span!( + self, + "#[napi(return_if_invalid)] can only be applied to a function or method." + ); + } + if opts.object().is_some() && opts.custom_finalize().is_some() { + bail_span!(self, "Custom finalize is not supported for #[napi(object)]"); + } let napi = self.convert_to_ast(opts); self.to_tokens(tokens); napi } } + impl ParseNapi for syn::ItemImpl { fn parse_napi(&mut self, tokens: &mut TokenStream, opts: BindgenAttrs) -> BindgenResult { if opts.ts_args_type().is_some() || opts.ts_return_type().is_some() || opts.skip_typescript().is_some() || opts.ts_type().is_some() + || opts.custom_finalize().is_some() { bail_span!( self, - "#[napi] can't be applied to impl with #[napi(ts_args_type)], #[napi(ts_return_type)], #[napi(skip_typescript)] or #[napi(ts_type)]" + "#[napi] can't be applied to impl with #[napi(ts_args_type)], #[napi(ts_return_type)], #[napi(skip_typescript)] or #[napi(ts_type)] or #[napi(custom_finalize)]" + ); + } + if opts.return_if_invalid().is_some() { + bail_span!( + self, + "#[napi(return_if_invalid)] can only be applied to a function or method." ); } // #[napi] macro will be remove from impl items after converted to ast @@ -766,13 +783,23 @@ impl ParseNapi for syn::ItemImpl { napi } } + impl ParseNapi for syn::ItemEnum { fn parse_napi(&mut self, tokens: &mut TokenStream, opts: BindgenAttrs) -> BindgenResult { - if opts.ts_args_type().is_some() || opts.ts_return_type().is_some() || opts.ts_type().is_some() + if opts.ts_args_type().is_some() + || opts.ts_return_type().is_some() + || opts.ts_type().is_some() + || opts.custom_finalize().is_some() { bail_span!( self, - "#[napi] can't be applied to a enum with #[napi(ts_args_type)], #[napi(ts_return_type)] or #[napi(ts_type)]" + "#[napi] can't be applied to a enum with #[napi(ts_args_type)], #[napi(ts_return_type)] or #[napi(ts_type)] or #[napi(custom_finalize)]" + ); + } + if opts.return_if_invalid().is_some() { + bail_span!( + self, + "#[napi(return_if_invalid)] can only be applied to a function or method." ); } let napi = self.convert_to_ast(opts); @@ -783,11 +810,20 @@ impl ParseNapi for syn::ItemEnum { } impl ParseNapi for syn::ItemConst { fn parse_napi(&mut self, tokens: &mut TokenStream, opts: BindgenAttrs) -> BindgenResult { - if opts.ts_args_type().is_some() || opts.ts_return_type().is_some() || opts.ts_type().is_some() + if opts.ts_args_type().is_some() + || opts.ts_return_type().is_some() + || opts.ts_type().is_some() + || opts.custom_finalize().is_some() { bail_span!( self, - "#[napi] can't be applied to a const with #[napi(ts_args_type)], #[napi(ts_return_type)] or #[napi(ts_type)]" + "#[napi] can't be applied to a const with #[napi(ts_args_type)], #[napi(ts_return_type)] or #[napi(ts_type)] or #[napi(custom_finalize)]" + ); + } + if opts.return_if_invalid().is_some() { + bail_span!( + self, + "#[napi(return_if_invalid)] can only be applied to a function or method." ); } let napi = self.convert_to_ast(opts); @@ -930,6 +966,7 @@ impl ConvertToAST for syn::ItemStruct { js_mod: namespace, comments: extract_doc_comments(&self.attrs), implement_iterator, + use_custom_finalize: opts.custom_finalize().is_some(), }), }) } diff --git a/crates/napi/src/bindgen_runtime/callback_info.rs b/crates/napi/src/bindgen_runtime/callback_info.rs index d869050f..08363745 100644 --- a/crates/napi/src/bindgen_runtime/callback_info.rs +++ b/crates/napi/src/bindgen_runtime/callback_info.rs @@ -67,7 +67,11 @@ impl CallbackInfo { self.this } - fn _construct(&self, js_name: &str, obj: T) -> Result<(sys::napi_value, *mut T)> { + fn _construct( + &self, + js_name: &str, + obj: T, + ) -> Result<(sys::napi_value, *mut T)> { let obj = Box::new(obj); let this = self.this(); let value_ref = Box::into_raw(obj); @@ -96,11 +100,15 @@ impl CallbackInfo { Ok((this, value_ref)) } - pub fn construct(&self, js_name: &str, obj: T) -> Result { + pub fn construct( + &self, + js_name: &str, + obj: T, + ) -> Result { self._construct(js_name, obj).map(|(v, _)| v) } - pub fn construct_generator( + pub fn construct_generator( &self, js_name: &str, obj: T, @@ -110,11 +118,15 @@ impl CallbackInfo { Ok(instance) } - pub fn factory(&self, js_name: &str, obj: T) -> Result { + pub fn factory( + &self, + js_name: &str, + obj: T, + ) -> Result { self._factory(js_name, obj).map(|(value, _)| value) } - pub fn generator_factory( + pub fn generator_factory( &self, js_name: &str, obj: T, @@ -124,7 +136,11 @@ impl CallbackInfo { Ok(instance) } - fn _factory(&self, js_name: &str, obj: T) -> Result<(sys::napi_value, *mut T)> { + fn _factory( + &self, + js_name: &str, + obj: T, + ) -> Result<(sys::napi_value, *mut T)> { let this = self.this(); let mut instance = ptr::null_mut(); let inner = ___CALL_FROM_FACTORY.get_or_default(); diff --git a/crates/napi/src/bindgen_runtime/mod.rs b/crates/napi/src/bindgen_runtime/mod.rs index 60630802..b007201e 100644 --- a/crates/napi/src/bindgen_runtime/mod.rs +++ b/crates/napi/src/bindgen_runtime/mod.rs @@ -11,7 +11,7 @@ pub use js_values::*; pub use module_register::*; use super::sys; -use crate::Status; +use crate::{JsError, Result, Status}; mod callback_info; mod env; @@ -20,16 +20,27 @@ pub mod iterator; mod js_values; mod module_register; +pub trait ObjectFinalize: Sized { + #[allow(unused)] + fn finalize(self, env: Env) -> Result<()> { + Ok(()) + } +} + /// # Safety /// /// called when node wrapper objects destroyed #[doc(hidden)] -pub unsafe extern "C" fn raw_finalize_unchecked( +pub unsafe extern "C" fn raw_finalize_unchecked( env: sys::napi_env, finalize_data: *mut c_void, _finalize_hint: *mut c_void, ) { - unsafe { Box::from_raw(finalize_data as *mut T) }; + let data = *unsafe { Box::from_raw(finalize_data as *mut T) }; + if let Err(err) = data.finalize(unsafe { Env::from_raw(env) }) { + let e: JsError = err.into(); + unsafe { e.throw_into(env) }; + } if let Some((_, ref_val, finalize_callbacks_ptr)) = REFERENCE_MAP.borrow_mut(|reference_map| reference_map.remove(&finalize_data)) { diff --git a/examples/napi/__test__/typegen.spec.ts.md b/examples/napi/__test__/typegen.spec.ts.md index bfa3b602..335a908a 100644 --- a/examples/napi/__test__/typegen.spec.ts.md +++ b/examples/napi/__test__/typegen.spec.ts.md @@ -294,6 +294,9 @@ Generated by [AVA](https://avajs.dev). constructor(name: string)␊ setName(name: string): void␊ }␊ + export class CustomFinalize {␊ + constructor(width: number, height: number)␊ + }␊ export class ClassWithFactory {␊ name: string␊ static withName(name: string): ClassWithFactory␊ diff --git a/examples/napi/__test__/typegen.spec.ts.snap b/examples/napi/__test__/typegen.spec.ts.snap index 8a9b5be2004743d3d5dba552ee91d92b7cc4cef8..77b9d6a1502dad84611b3c2805597b7e8c05a00e 100644 GIT binary patch literal 3515 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 OcmEF+g^#?~F#rJaOvYva diff --git a/examples/napi/__test__/values.spec.ts b/examples/napi/__test__/values.spec.ts index 459e4c68..e688c6f7 100644 --- a/examples/napi/__test__/values.spec.ts +++ b/examples/napi/__test__/values.spec.ts @@ -107,6 +107,7 @@ import { useTokioWithoutAsync, getNumArr, getNestedNumArr, + CustomFinalize, } from '../' test('export const', (t) => { @@ -241,6 +242,10 @@ test('class in object field', (t) => { t.is(receiveObjectWithClassField(obj), obj.bird) }) +test('custom finalize class', (t) => { + t.notThrows(() => new CustomFinalize(200, 200)) +}) + test('should be able to create object reference and shared reference', (t) => { const repo = new JsRepo('.') t.is(repo.remote().name(), 'origin') diff --git a/examples/napi/index.d.ts b/examples/napi/index.d.ts index f653f1bb..ca259111 100644 --- a/examples/napi/index.d.ts +++ b/examples/napi/index.d.ts @@ -284,6 +284,9 @@ export class NotWritableClass { constructor(name: string) setName(name: string): void } +export class CustomFinalize { + constructor(width: number, height: number) +} export class ClassWithFactory { name: string static withName(name: string): ClassWithFactory diff --git a/examples/napi/src/class.rs b/examples/napi/src/class.rs index a1ae310c..01ed6b6d 100644 --- a/examples/napi/src/class.rs +++ b/examples/napi/src/class.rs @@ -1,5 +1,5 @@ use napi::{ - bindgen_prelude::{Buffer, ClassInstance, This, Uint8Array}, + bindgen_prelude::{Buffer, ClassInstance, ObjectFinalize, This, Uint8Array}, Env, Result, }; @@ -361,3 +361,32 @@ impl NotWritableClass { self.name = name; } } + +#[napi(custom_finalize)] +pub struct CustomFinalize { + width: u32, + height: u32, + inner: Vec, +} + +#[napi] +impl CustomFinalize { + #[napi(constructor)] + pub fn new(mut env: Env, width: u32, height: u32) -> Result { + let inner = vec![0; (width * height * 4) as usize]; + let inner_size = inner.len(); + env.adjust_external_memory(inner_size as i64)?; + Ok(Self { + width, + height, + inner, + }) + } +} + +impl ObjectFinalize for CustomFinalize { + fn finalize(self, mut env: Env) -> Result<()> { + env.adjust_external_memory(-(self.inner.len() as i64))?; + Ok(()) + } +}