Merge pull request #104 from messense/feature/catch-unwind
Throw exception when Rust code panics
This commit is contained in:
commit
5e0ec94db1
5 changed files with 33 additions and 7 deletions
|
@ -4,9 +4,9 @@
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate napi_rs as napi;
|
extern crate napi;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate napi_rs_derive;
|
extern crate napi_derive;
|
||||||
|
|
||||||
use napi::{CallContext, Error, JsNumber, JsUnknown, Module, Result, Status};
|
use napi::{CallContext, Error, JsNumber, JsUnknown, Module, Result, Status};
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
|
|
|
@ -89,8 +89,9 @@ pub fn js_function(attr: TokenStream, input: TokenStream) -> TokenStream {
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::os::raw::c_char;
|
use std::os::raw::c_char;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
use std::panic::{self, AssertUnwindSafe};
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
use napi::{JsUnknown, Env, Status, NapiValue, CallContext};
|
use napi::{JsUnknown, Env, Error, Status, NapiValue, CallContext};
|
||||||
let mut argc = #arg_len_span as usize;
|
let mut argc = #arg_len_span as usize;
|
||||||
let mut raw_args =
|
let mut raw_args =
|
||||||
unsafe { mem::MaybeUninit::<[napi::sys::napi_value; #arg_len_span as usize]>::uninit().assume_init() };
|
unsafe { mem::MaybeUninit::<[napi::sys::napi_value; #arg_len_span as usize]>::uninit().assume_init() };
|
||||||
|
@ -112,7 +113,23 @@ pub fn js_function(attr: TokenStream, input: TokenStream) -> TokenStream {
|
||||||
|
|
||||||
let mut env = Env::from_raw(raw_env);
|
let mut env = Env::from_raw(raw_env);
|
||||||
let call_ctx = CallContext::new(&mut env, raw_this, &raw_args, #arg_len_span, argc as usize);
|
let call_ctx = CallContext::new(&mut env, raw_this, &raw_args, #arg_len_span, argc as usize);
|
||||||
let result = call_ctx.and_then(|ctx| #new_fn_name(ctx));
|
let result = call_ctx.and_then(|ctx| {
|
||||||
|
match panic::catch_unwind(AssertUnwindSafe(move || #new_fn_name(ctx))) {
|
||||||
|
Ok(result) => result,
|
||||||
|
Err(e) => {
|
||||||
|
let message = {
|
||||||
|
if let Some(string) = e.downcast_ref::<String>() {
|
||||||
|
string.clone()
|
||||||
|
} else if let Some(string) = e.downcast_ref::<&str>() {
|
||||||
|
string.to_string()
|
||||||
|
} else {
|
||||||
|
format!("panic from Rust code: {:?}", e)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Err(Error { status: Status::GenericFailure, reason: message })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
has_error = has_error && result.is_err();
|
has_error = has_error && result.is_err();
|
||||||
|
|
||||||
match result {
|
match result {
|
||||||
|
|
|
@ -20,10 +20,10 @@ pub trait ToJs: Copy + Clone {
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// #[macro_use]
|
/// #[macro_use]
|
||||||
/// extern crate napi_rs_derive;
|
/// extern crate napi_derive;
|
||||||
///
|
///
|
||||||
/// use std::thread;
|
/// use std::thread;
|
||||||
/// use napi_rs::{
|
/// use napi::{
|
||||||
/// Number, Result, Env, CallContext, JsUndefined, JsFunction,
|
/// Number, Result, Env, CallContext, JsUndefined, JsFunction,
|
||||||
/// sys::{
|
/// sys::{
|
||||||
/// napi_threadsafe_function_call_mode::{
|
/// napi_threadsafe_function_call_mode::{
|
||||||
|
@ -34,7 +34,7 @@ pub trait ToJs: Copy + Clone {
|
||||||
/// }
|
/// }
|
||||||
/// }
|
/// }
|
||||||
/// };
|
/// };
|
||||||
/// use napi_rs::threadsafe_function::{
|
/// use napi::threadsafe_function::{
|
||||||
/// ToJs, ThreadsafeFunction,
|
/// ToJs, ThreadsafeFunction,
|
||||||
/// };
|
/// };
|
||||||
///
|
///
|
||||||
|
|
|
@ -14,3 +14,7 @@ test('should be able to throw error from native with reason', (t) => {
|
||||||
test('should throw if argument type is not match', (t) => {
|
test('should throw if argument type is not match', (t) => {
|
||||||
t.throws(() => bindings.testThrowWithReason(2))
|
t.throws(() => bindings.testThrowWithReason(2))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('should throw if Rust code panic', (t) => {
|
||||||
|
t.throws(() => bindings.testThrowWithPanic())
|
||||||
|
})
|
||||||
|
|
|
@ -86,3 +86,8 @@ fn test_throw_with_reason(ctx: CallContext) -> Result<JsUnknown> {
|
||||||
reason.as_str()?.to_owned(),
|
reason.as_str()?.to_owned(),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[js_function]
|
||||||
|
pub fn test_throw_with_panic(_ctx: CallContext) -> Result<JsUnknown> {
|
||||||
|
panic!("don't panic.");
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue