From 97659e477f2c1e97147e88b57325dbb0069e9c9a Mon Sep 17 00:00:00 2001 From: LongYinan Date: Fri, 19 Aug 2022 11:21:25 +0800 Subject: [PATCH] feat(napi-derive): catch_unwind attribute --- crates/backend/src/ast.rs | 1 + crates/backend/src/codegen/fn.rs | 14 ++++++++++ crates/macro/src/parser/attrs.rs | 1 + crates/macro/src/parser/mod.rs | 25 ++++++++++++++++++ .../src/bindgen_runtime/module_register.rs | 2 +- crates/napi/src/env.rs | 2 +- examples/napi/__test__/typegen.spec.ts.md | 1 + examples/napi/__test__/typegen.spec.ts.snap | Bin 3557 -> 3566 bytes examples/napi/__test__/values.spec.ts | 4 ++- examples/napi/index.d.ts | 1 + examples/napi/src/error.rs | 7 ++++- examples/napi/src/lib.rs | 2 +- 12 files changed, 55 insertions(+), 5 deletions(-) diff --git a/crates/backend/src/ast.rs b/crates/backend/src/ast.rs index 101dfc5472..544c95888c 100644 --- a/crates/backend/src/ast.rs +++ b/crates/backend/src/ast.rs @@ -26,6 +26,7 @@ pub struct NapiFn { pub writable: bool, pub enumerable: bool, pub configurable: bool, + pub catch_unwind: bool, } #[derive(Debug, Clone)] diff --git a/crates/backend/src/codegen/fn.rs b/crates/backend/src/codegen/fn.rs index 0c7e48a4ae..7fbb03444a 100644 --- a/crates/backend/src/codegen/fn.rs +++ b/crates/backend/src/codegen/fn.rs @@ -69,6 +69,20 @@ impl TryToTokens for NapiFn { } }; + let function_call = if self.catch_unwind { + quote! { + { + std::panic::catch_unwind(|| { #function_call }) + .map_err(|e| napi::Error::new(napi::Status::GenericFailure, format!("{:?}", e))) + .and_then(|r| r) + } + } + } else { + quote! { + #function_call + } + }; + (quote! { #(#attrs)* #[doc(hidden)] diff --git a/crates/macro/src/parser/attrs.rs b/crates/macro/src/parser/attrs.rs index f7e2a7e0cf..c9c6fd04ac 100644 --- a/crates/macro/src/parser/attrs.rs +++ b/crates/macro/src/parser/attrs.rs @@ -42,6 +42,7 @@ pub struct BindgenAttrs { macro_rules! attrgen { ($mac:ident) => { $mac! { + (catch_unwind, CatchUnwind(Span)), (js_name, JsName(Span, String, Span)), (constructor, Constructor(Span)), (factory, Factory(Span)), diff --git a/crates/macro/src/parser/mod.rs b/crates/macro/src/parser/mod.rs index ec91abfd9f..a38db36a43 100644 --- a/crates/macro/src/parser/mod.rs +++ b/crates/macro/src/parser/mod.rs @@ -695,6 +695,7 @@ fn napi_fn_from_decl( writable: opts.writable(), enumerable: opts.enumerable(), configurable: opts.configurable(), + catch_unwind: opts.catch_unwind().is_some(), } }) } @@ -747,6 +748,12 @@ impl ParseNapi for syn::ItemStruct { "#[napi(return_if_invalid)] can only be applied to a function or method." ); } + if opts.catch_unwind().is_some() { + bail_span!( + self, + "#[napi(catch_unwind)] 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)]"); } @@ -776,6 +783,12 @@ impl ParseNapi for syn::ItemImpl { "#[napi(return_if_invalid)] can only be applied to a function or method." ); } + if opts.catch_unwind().is_some() { + bail_span!( + self, + "#[napi(catch_unwind)] can only be applied to a function or method." + ); + } // #[napi] macro will be remove from impl items after converted to ast let napi = self.convert_to_ast(opts); self.to_tokens(tokens); @@ -802,6 +815,12 @@ impl ParseNapi for syn::ItemEnum { "#[napi(return_if_invalid)] can only be applied to a function or method." ); } + if opts.catch_unwind().is_some() { + bail_span!( + self, + "#[napi(catch_unwind)] can only be applied to a function or method." + ); + } let napi = self.convert_to_ast(opts); self.to_tokens(tokens); @@ -826,6 +845,12 @@ impl ParseNapi for syn::ItemConst { "#[napi(return_if_invalid)] can only be applied to a function or method." ); } + if opts.catch_unwind().is_some() { + bail_span!( + self, + "#[napi(catch_unwind)] can only be applied to a function or method." + ); + } let napi = self.convert_to_ast(opts); self.to_tokens(tokens); napi diff --git a/crates/napi/src/bindgen_runtime/module_register.rs b/crates/napi/src/bindgen_runtime/module_register.rs index d3d609e02f..27bca024ed 100644 --- a/crates/napi/src/bindgen_runtime/module_register.rs +++ b/crates/napi/src/bindgen_runtime/module_register.rs @@ -38,7 +38,7 @@ impl PersistedSingleThreadVec { .inner .lock() .expect("Acquire persisted thread vec lock failed"); - f(&mut *locked); + f(&mut locked); } fn push(&self, item: T) { diff --git a/crates/napi/src/env.rs b/crates/napi/src/env.rs index e9294e28f0..88b6a1d4b3 100644 --- a/crates/napi/src/env.rs +++ b/crates/napi/src/env.rs @@ -854,7 +854,7 @@ impl Env { ))?; let type_id = unknown_tagged_object as *const TypeId; if *type_id == TypeId::of::() { - Box::from_raw(unknown_tagged_object as *mut TaggedObject); + drop(Box::from_raw(unknown_tagged_object as *mut TaggedObject)); Ok(()) } else { Err(Error::new( diff --git a/examples/napi/__test__/typegen.spec.ts.md b/examples/napi/__test__/typegen.spec.ts.md index 839b73dbd1..a05091fdd2 100644 --- a/examples/napi/__test__/typegen.spec.ts.md +++ b/examples/napi/__test__/typegen.spec.ts.md @@ -103,6 +103,7 @@ Generated by [AVA](https://avajs.dev). }␊ export function enumToI32(e: CustomNumEnum): number␊ export function throwError(): void␊ + export function panic(): void␊ export function createExternal(size: number): ExternalObject␊ export function createExternalString(content: string): ExternalObject␊ export function getExternal(external: ExternalObject): number␊ diff --git a/examples/napi/__test__/typegen.spec.ts.snap b/examples/napi/__test__/typegen.spec.ts.snap index 4b49767a2c08c17091d3f0614cac63df8cd0dc46..69867ce3d6c6ff36fa1635edbfc40b60620c4856 100644 GIT binary patch literal 3566 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 literal 3557 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 diff --git a/examples/napi/__test__/values.spec.ts b/examples/napi/__test__/values.spec.ts index 2b884642ef..a0504d9ac9 100644 --- a/examples/napi/__test__/values.spec.ts +++ b/examples/napi/__test__/values.spec.ts @@ -31,6 +31,7 @@ import { mapOption, readFile, throwError, + panic, readPackageJson, getPackageJsonName, getBuffer, @@ -163,7 +164,7 @@ test('enum', (t) => { t.is(enumToI32(CustomNumEnum.Eight), 8) }) -test.only('class', (t) => { +test('class', (t) => { const dog = new Animal(Kind.Dog, '旺财') t.is(dog.name, '旺财') @@ -371,6 +372,7 @@ test('Option', (t) => { test('Result', (t) => { t.throws(() => throwError(), void 0, 'Manual Error') + t.throws(() => panic(), void 0, `Don't panic`) }) test('function ts type override', (t) => { diff --git a/examples/napi/index.d.ts b/examples/napi/index.d.ts index 970ce77a52..30690e82a8 100644 --- a/examples/napi/index.d.ts +++ b/examples/napi/index.d.ts @@ -93,6 +93,7 @@ export const enum CustomNumEnum { } export function enumToI32(e: CustomNumEnum): number export function throwError(): void +export function panic(): void export function createExternal(size: number): ExternalObject export function createExternalString(content: string): ExternalObject export function getExternal(external: ExternalObject): number diff --git a/examples/napi/src/error.rs b/examples/napi/src/error.rs index e1533117db..42aa4ef19e 100644 --- a/examples/napi/src/error.rs +++ b/examples/napi/src/error.rs @@ -1,6 +1,11 @@ use napi::bindgen_prelude::*; #[napi] -fn throw_error() -> Result<()> { +pub fn throw_error() -> Result<()> { Err(Error::new(Status::InvalidArg, "Manual Error".to_owned())) } + +#[napi(catch_unwind)] +pub fn panic() { + panic!("Don't panic"); +} diff --git a/examples/napi/src/lib.rs b/examples/napi/src/lib.rs index 1825406c07..48f23ca502 100644 --- a/examples/napi/src/lib.rs +++ b/examples/napi/src/lib.rs @@ -1,6 +1,6 @@ #![allow(dead_code)] #![allow(unreachable_code)] -#![allow(clippy::blacklisted_name)] +#![allow(clippy::disallowed_names)] #[macro_use] extern crate napi_derive;