Merge pull request #330 from napi-rs/refactor-js-error
refactor(napi): js error
This commit is contained in:
commit
4d35b28ae4
18 changed files with 311 additions and 64 deletions
|
@ -86,6 +86,7 @@ pub fn js_function(attr: TokenStream, input: TokenStream) -> TokenStream {
|
||||||
let new_fn_name = signature.ident.clone();
|
let new_fn_name = signature.ident.clone();
|
||||||
let execute_js_function = get_execute_js_code(new_fn_name, FunctionKind::JsFunction);
|
let execute_js_function = get_execute_js_code(new_fn_name, FunctionKind::JsFunction);
|
||||||
let expanded = quote! {
|
let expanded = quote! {
|
||||||
|
#[inline(always)]
|
||||||
#signature #(#fn_block)*
|
#signature #(#fn_block)*
|
||||||
|
|
||||||
#visibility extern "C" fn #fn_name(
|
#visibility extern "C" fn #fn_name(
|
||||||
|
@ -134,6 +135,7 @@ pub fn contextless_function(_attr: TokenStream, input: TokenStream) -> TokenStre
|
||||||
let execute_js_function = get_execute_js_code(new_fn_name, FunctionKind::Contextless);
|
let execute_js_function = get_execute_js_code(new_fn_name, FunctionKind::Contextless);
|
||||||
|
|
||||||
let expanded = quote! {
|
let expanded = quote! {
|
||||||
|
#[inline(always)]
|
||||||
#signature #(#fn_block)*
|
#signature #(#fn_block)*
|
||||||
|
|
||||||
#visibility extern "C" fn #fn_name(
|
#visibility extern "C" fn #fn_name(
|
||||||
|
@ -191,10 +193,7 @@ fn get_execute_js_code(
|
||||||
}).and_then(|v| v) {
|
}).and_then(|v| v) {
|
||||||
#return_token_stream
|
#return_token_stream
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
let message = format!("{}", e);
|
unsafe { napi::JsError::from(e).throw_into(raw_env) };
|
||||||
unsafe {
|
|
||||||
napi::sys::napi_throw_error(raw_env, ptr::null(), CString::from_vec_unchecked(message.into()).as_ptr());
|
|
||||||
}
|
|
||||||
ptr::null_mut()
|
ptr::null_mut()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,7 @@ use std::mem;
|
||||||
use std::os::raw::{c_char, c_void};
|
use std::os::raw::{c_char, c_void};
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
||||||
use crate::check_status;
|
use crate::{check_status, js_values::NapiValue, sys, Env, JsError, JsObject, Result, Task};
|
||||||
use crate::js_values::NapiValue;
|
|
||||||
use crate::{sys, Env, JsObject, Result, Task};
|
|
||||||
|
|
||||||
struct AsyncWork<T: Task> {
|
struct AsyncWork<T: Task> {
|
||||||
inner_task: T,
|
inner_task: T,
|
||||||
|
@ -110,7 +108,7 @@ unsafe extern "C" fn complete<T: Task>(
|
||||||
debug_assert!(status == sys::Status::napi_ok, "Reject promise failed");
|
debug_assert!(status == sys::Status::napi_ok, "Reject promise failed");
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
let status = sys::napi_reject_deferred(env, deferred, e.into_raw(env));
|
let status = sys::napi_reject_deferred(env, deferred, JsError::from(e).into_value(env));
|
||||||
debug_assert!(status == sys::Status::napi_ok, "Reject promise failed");
|
debug_assert!(status == sys::Status::napi_ok, "Reject promise failed");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
110
napi/src/env.rs
110
napi/src/env.rs
|
@ -4,11 +4,14 @@ use std::ffi::CString;
|
||||||
use std::os::raw::{c_char, c_void};
|
use std::os::raw::{c_char, c_void};
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
||||||
use crate::async_work::{self, AsyncWorkPromise};
|
use crate::{
|
||||||
use crate::check_status;
|
async_work::{self, AsyncWorkPromise},
|
||||||
use crate::js_values::*;
|
check_status,
|
||||||
use crate::task::Task;
|
js_values::*,
|
||||||
use crate::{sys, Error, NodeVersion, Result, Status};
|
sys,
|
||||||
|
task::Task,
|
||||||
|
Error, ExtendedErrorInfo, NodeVersion, Result, Status,
|
||||||
|
};
|
||||||
|
|
||||||
#[cfg(feature = "napi3")]
|
#[cfg(feature = "napi3")]
|
||||||
use super::cleanup_env::{CleanupEnvHook, CleanupEnvHookData};
|
use super::cleanup_env::{CleanupEnvHook, CleanupEnvHookData};
|
||||||
|
@ -255,6 +258,7 @@ impl Env {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
/// This API allocates a node::Buffer object. While this is still a fully-supported data structure, in most cases using a TypedArray will suffice.
|
||||||
pub fn create_buffer(&self, length: usize) -> Result<JsBufferValue> {
|
pub fn create_buffer(&self, length: usize) -> Result<JsBufferValue> {
|
||||||
let mut raw_value = ptr::null_mut();
|
let mut raw_value = ptr::null_mut();
|
||||||
let mut data: Vec<u8> = Vec::with_capacity(length);
|
let mut data: Vec<u8> = Vec::with_capacity(length);
|
||||||
|
@ -274,6 +278,8 @@ impl Env {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
/// This API allocates a node::Buffer object and initializes it with data backed by the passed in buffer.
|
||||||
|
/// While this is still a fully-supported data structure, in most cases using a TypedArray will suffice.
|
||||||
pub fn create_buffer_with_data(&self, mut data: Vec<u8>) -> Result<JsBufferValue> {
|
pub fn create_buffer_with_data(&self, mut data: Vec<u8>) -> Result<JsBufferValue> {
|
||||||
let mut length = data.len();
|
let mut length = data.len();
|
||||||
let mut raw_value = ptr::null_mut();
|
let mut raw_value = ptr::null_mut();
|
||||||
|
@ -303,6 +309,8 @@ impl Env {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
/// This API allocates a node::Buffer object and initializes it with data copied from the passed-in buffer.
|
||||||
|
/// While this is still a fully-supported data structure, in most cases using a TypedArray will suffice.
|
||||||
pub fn create_buffer_copy<D>(&self, data_to_copy: D) -> Result<JsBufferValue>
|
pub fn create_buffer_copy<D>(&self, data_to_copy: D) -> Result<JsBufferValue>
|
||||||
where
|
where
|
||||||
D: AsRef<[u8]>,
|
D: AsRef<[u8]>,
|
||||||
|
@ -376,6 +384,10 @@ impl Env {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
/// This API allows an add-on author to create a function object in native code.
|
||||||
|
/// This is the primary mechanism to allow calling into the add-on's native code from JavaScript.
|
||||||
|
/// The newly created function is not automatically visible from script after this call.
|
||||||
|
/// Instead, a property must be explicitly set on any object that is visible to JavaScript, in order for the function to be accessible from script.
|
||||||
pub fn create_function(&self, name: &str, callback: Callback) -> Result<JsFunction> {
|
pub fn create_function(&self, name: &str, callback: Callback) -> Result<JsFunction> {
|
||||||
let mut raw_result = ptr::null_mut();
|
let mut raw_result = ptr::null_mut();
|
||||||
let len = name.len();
|
let len = name.len();
|
||||||
|
@ -395,19 +407,94 @@ impl Env {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn throw(&self, error: Error) -> Result<()> {
|
/// This API retrieves a napi_extended_error_info structure with information about the last error that occurred.
|
||||||
let err_value = self.create_error(error)?.0.value;
|
/// The content of the napi_extended_error_info returned is only valid up until an n-api function is called on the same env.
|
||||||
check_status!(unsafe { sys::napi_throw(self.0, err_value) })?;
|
/// Do not rely on the content or format of any of the extended information as it is not subject to SemVer and may change at any time. It is intended only for logging purposes.
|
||||||
Ok(())
|
/// This API can be called even if there is a pending JavaScript exception.
|
||||||
|
pub fn get_last_error_info(&self) -> Result<ExtendedErrorInfo> {
|
||||||
|
let mut raw_extended_error = ptr::null();
|
||||||
|
check_status!(unsafe { sys::napi_get_last_error_info(self.0, &mut raw_extended_error) })?;
|
||||||
|
unsafe { ptr::read(raw_extended_error) }.try_into()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn throw_error(&self, msg: &str) -> Result<()> {
|
/// This API throws a JavaScript Error with the text provided.
|
||||||
|
pub fn throw_error(&self, msg: &str, code: Option<&str>) -> Result<()> {
|
||||||
check_status!(unsafe {
|
check_status!(unsafe {
|
||||||
sys::napi_throw_error(self.0, ptr::null(), CString::new(msg)?.as_ptr())
|
sys::napi_throw_error(
|
||||||
|
self.0,
|
||||||
|
match code {
|
||||||
|
Some(s) => CString::new(s)?.as_ptr(),
|
||||||
|
None => ptr::null_mut(),
|
||||||
|
},
|
||||||
|
CString::new(msg)?.as_ptr(),
|
||||||
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
/// This API throws a JavaScript RangeError with the text provided.
|
||||||
|
pub fn throw_range_error(&self, msg: &str, code: Option<&str>) -> Result<()> {
|
||||||
|
check_status!(unsafe {
|
||||||
|
sys::napi_throw_range_error(
|
||||||
|
self.0,
|
||||||
|
match code {
|
||||||
|
Some(s) => CString::new(s)?.as_ptr(),
|
||||||
|
None => ptr::null_mut(),
|
||||||
|
},
|
||||||
|
CString::new(msg)?.as_ptr(),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
/// This API throws a JavaScript TypeError with the text provided.
|
||||||
|
pub fn throw_type_error(&self, msg: &str, code: Option<&str>) -> Result<()> {
|
||||||
|
check_status!(unsafe {
|
||||||
|
sys::napi_throw_type_error(
|
||||||
|
self.0,
|
||||||
|
match code {
|
||||||
|
Some(s) => CString::new(s)?.as_ptr(),
|
||||||
|
None => ptr::null_mut(),
|
||||||
|
},
|
||||||
|
CString::new(msg)?.as_ptr(),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
#[allow(clippy::expect_fun_call)]
|
||||||
|
/// In the event of an unrecoverable error in a native module
|
||||||
|
/// A fatal error can be thrown to immediately terminate the process.
|
||||||
|
pub fn fatal_error(self, location: &str, message: &str) {
|
||||||
|
let location_len = location.len();
|
||||||
|
let message_len = message.len();
|
||||||
|
let location =
|
||||||
|
CString::new(location).expect(format!("Convert [{}] to CString failed", location).as_str());
|
||||||
|
let message =
|
||||||
|
CString::new(message).expect(format!("Convert [{}] to CString failed", message).as_str());
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
sys::napi_fatal_error(
|
||||||
|
location.as_ptr(),
|
||||||
|
location_len,
|
||||||
|
message.as_ptr(),
|
||||||
|
message_len,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "napi3")]
|
||||||
|
#[inline]
|
||||||
|
/// Trigger an 'uncaughtException' in JavaScript.
|
||||||
|
/// Useful if an async callback throws an exception with no way to recover.
|
||||||
|
pub fn fatal_exception(&self, err: Error) {
|
||||||
|
unsafe {
|
||||||
|
let js_error = JsError::from(err).into_value(self.0);
|
||||||
|
debug_assert!(sys::napi_fatal_exception(self.0, js_error) == sys::Status::napi_ok);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn define_class(
|
pub fn define_class(
|
||||||
&self,
|
&self,
|
||||||
|
@ -757,6 +844,7 @@ impl Env {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
/// This API represents the invocation of the Strict Equality algorithm as defined in [Section 7.2.14](https://tc39.es/ecma262/#sec-strict-equality-comparison) of the ECMAScript Language Specification.
|
||||||
pub fn strict_equals<A: NapiValue, B: NapiValue>(&self, a: A, b: B) -> Result<bool> {
|
pub fn strict_equals<A: NapiValue, B: NapiValue>(&self, a: A, b: B) -> Result<bool> {
|
||||||
let mut result = false;
|
let mut result = false;
|
||||||
check_status!(unsafe { sys::napi_strict_equals(self.0, a.raw(), b.raw(), &mut result) })?;
|
check_status!(unsafe { sys::napi_strict_equals(self.0, a.raw(), b.raw(), &mut result) })?;
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
use std::convert::From;
|
use std::convert::{From, TryFrom};
|
||||||
use std::error;
|
use std::error;
|
||||||
|
use std::ffi::CString;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
#[cfg(feature = "serde-json")]
|
#[cfg(feature = "serde-json")]
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
use std::os::raw::c_char;
|
use std::os::raw::{c_char, c_void};
|
||||||
use std::ptr;
|
|
||||||
|
|
||||||
#[cfg(feature = "serde-json")]
|
#[cfg(feature = "serde-json")]
|
||||||
use serde::{de, ser};
|
use serde::{de, ser};
|
||||||
|
@ -37,7 +37,11 @@ impl de::Error for Error {
|
||||||
|
|
||||||
impl fmt::Display for Error {
|
impl fmt::Display for Error {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
write!(f, "{:?}: {}", self.status, self.reason)
|
if !self.reason.is_empty() {
|
||||||
|
write!(f, "{:?}, {}", self.status, self.reason)
|
||||||
|
} else {
|
||||||
|
write!(f, "{:?}", self.status)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,25 +66,6 @@ impl Error {
|
||||||
reason,
|
reason,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub(crate) fn into_raw(self, env: sys::napi_env) -> sys::napi_value {
|
|
||||||
let mut err = ptr::null_mut();
|
|
||||||
let s = self.reason;
|
|
||||||
unsafe {
|
|
||||||
let mut err_reason = ptr::null_mut();
|
|
||||||
let status = sys::napi_create_string_utf8(
|
|
||||||
env,
|
|
||||||
s.as_ptr() as *const c_char,
|
|
||||||
s.len() as _,
|
|
||||||
&mut err_reason,
|
|
||||||
);
|
|
||||||
debug_assert!(status == sys::Status::napi_ok, "Create error reason failed");
|
|
||||||
let status = sys::napi_create_error(env, ptr::null_mut(), err_reason, &mut err);
|
|
||||||
debug_assert!(status == sys::Status::napi_ok, "Create error failed");
|
|
||||||
};
|
|
||||||
err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<std::ffi::NulError> for Error {
|
impl From<std::ffi::NulError> for Error {
|
||||||
|
@ -101,6 +86,31 @@ impl From<std::io::Error> for Error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct ExtendedErrorInfo {
|
||||||
|
pub message: String,
|
||||||
|
pub engine_reserved: *mut c_void,
|
||||||
|
pub engine_error_code: u32,
|
||||||
|
pub error_code: Status,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<sys::napi_extended_error_info> for ExtendedErrorInfo {
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn try_from(value: sys::napi_extended_error_info) -> Result<Self> {
|
||||||
|
Ok(Self {
|
||||||
|
message: unsafe {
|
||||||
|
CString::from_raw(value.error_message as *mut c_char)
|
||||||
|
.into_string()
|
||||||
|
.map_err(|e| Error::new(Status::GenericFailure, format!("{}", e)))?
|
||||||
|
},
|
||||||
|
engine_error_code: value.engine_error_code,
|
||||||
|
engine_reserved: value.engine_reserved,
|
||||||
|
error_code: Status::from(value.error_code),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[macro_export(local_inner_macros)]
|
#[macro_export(local_inner_macros)]
|
||||||
macro_rules! check_status {
|
macro_rules! check_status {
|
||||||
|
|
89
napi/src/js_values/error.rs
Normal file
89
napi/src/js_values/error.rs
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
use std::ffi::CString;
|
||||||
|
use std::ptr;
|
||||||
|
|
||||||
|
use crate::{check_status, sys, Env, Error};
|
||||||
|
|
||||||
|
pub struct JsError(Error);
|
||||||
|
|
||||||
|
pub struct JsTypeError(Error);
|
||||||
|
|
||||||
|
pub struct JsRangeError(Error);
|
||||||
|
|
||||||
|
macro_rules! impl_object_methods {
|
||||||
|
($js_value:ident, $kind:expr) => {
|
||||||
|
impl $js_value {
|
||||||
|
#[inline(always)]
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// This function is safety if env is not null ptr.
|
||||||
|
pub unsafe fn into_value(self, env: sys::napi_env) -> sys::napi_value {
|
||||||
|
let error_status = format!("{:?}", self.0.status);
|
||||||
|
let status_len = error_status.len();
|
||||||
|
let error_code_string = CString::new(error_status).unwrap();
|
||||||
|
let reason_len = self.0.reason.len();
|
||||||
|
let reason = CString::new(self.0.reason).unwrap();
|
||||||
|
let mut error_code = ptr::null_mut();
|
||||||
|
let mut reason_string = ptr::null_mut();
|
||||||
|
let mut js_error = ptr::null_mut();
|
||||||
|
debug_assert!(
|
||||||
|
sys::napi_create_string_utf8(
|
||||||
|
env,
|
||||||
|
error_code_string.as_ptr(),
|
||||||
|
status_len,
|
||||||
|
&mut error_code
|
||||||
|
) == sys::Status::napi_ok
|
||||||
|
);
|
||||||
|
debug_assert!(
|
||||||
|
sys::napi_create_string_utf8(env, reason.as_ptr(), reason_len, &mut reason_string)
|
||||||
|
== sys::Status::napi_ok
|
||||||
|
);
|
||||||
|
debug_assert!($kind(env, error_code, reason_string, &mut js_error) == sys::Status::napi_ok);
|
||||||
|
js_error
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// This function is safety if env is not null ptr.
|
||||||
|
pub unsafe fn throw_into(self, env: sys::napi_env) {
|
||||||
|
let js_error = self.into_value(env);
|
||||||
|
debug_assert!(sys::napi_throw(env, js_error) == sys::Status::napi_ok);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn throw(&self, env: &Env) -> Result<(), Error> {
|
||||||
|
let error_status = format!("{:?}", self.0.status);
|
||||||
|
let status_len = error_status.len();
|
||||||
|
let error_code_string = CString::new(error_status).unwrap();
|
||||||
|
let reason_len = self.0.reason.len();
|
||||||
|
let reason = CString::new(self.0.reason.clone()).unwrap();
|
||||||
|
let mut error_code = ptr::null_mut();
|
||||||
|
let mut reason_string = ptr::null_mut();
|
||||||
|
let mut js_error = ptr::null_mut();
|
||||||
|
check_status!(unsafe {
|
||||||
|
sys::napi_create_string_utf8(
|
||||||
|
env.0,
|
||||||
|
error_code_string.as_ptr(),
|
||||||
|
status_len,
|
||||||
|
&mut error_code,
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
check_status!(unsafe {
|
||||||
|
sys::napi_create_string_utf8(env.0, reason.as_ptr(), reason_len, &mut reason_string)
|
||||||
|
})?;
|
||||||
|
check_status!(unsafe { $kind(env.0, error_code, reason_string, &mut js_error) })?;
|
||||||
|
check_status!(unsafe { sys::napi_throw(env.0, js_error) })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Error> for $js_value {
|
||||||
|
fn from(err: Error) -> Self {
|
||||||
|
Self(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_object_methods!(JsError, sys::napi_create_error);
|
||||||
|
impl_object_methods!(JsTypeError, sys::napi_create_type_error);
|
||||||
|
impl_object_methods!(JsRangeError, sys::napi_create_range_error);
|
|
@ -18,6 +18,7 @@ mod buffer;
|
||||||
#[cfg(feature = "napi5")]
|
#[cfg(feature = "napi5")]
|
||||||
mod date;
|
mod date;
|
||||||
mod either;
|
mod either;
|
||||||
|
mod error;
|
||||||
mod escapable_handle_scope;
|
mod escapable_handle_scope;
|
||||||
mod function;
|
mod function;
|
||||||
mod global;
|
mod global;
|
||||||
|
@ -41,6 +42,7 @@ pub use date::*;
|
||||||
#[cfg(feature = "serde-json")]
|
#[cfg(feature = "serde-json")]
|
||||||
pub(crate) use de::De;
|
pub(crate) use de::De;
|
||||||
pub use either::Either;
|
pub use either::Either;
|
||||||
|
pub use error::*;
|
||||||
pub use escapable_handle_scope::EscapableHandleScope;
|
pub use escapable_handle_scope::EscapableHandleScope;
|
||||||
pub use function::JsFunction;
|
pub use function::JsFunction;
|
||||||
pub use global::*;
|
pub use global::*;
|
||||||
|
@ -508,7 +510,9 @@ macro_rules! impl_object_methods {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_array_length_unchecked(&self) -> Result<u32> {
|
pub fn get_array_length_unchecked(&self) -> Result<u32> {
|
||||||
let mut length: u32 = 0;
|
let mut length: u32 = 0;
|
||||||
check_status!(unsafe { sys::napi_get_array_length(self.0.env, self.raw(), &mut length) })?;
|
check_status!(unsafe {
|
||||||
|
sys::napi_get_array_length(self.0.env, self.0.value, &mut length)
|
||||||
|
})?;
|
||||||
Ok(length)
|
Ok(length)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -118,7 +118,7 @@ pub use napi_sys as sys;
|
||||||
|
|
||||||
pub use call_context::CallContext;
|
pub use call_context::CallContext;
|
||||||
pub use env::*;
|
pub use env::*;
|
||||||
pub use error::{Error, Result};
|
pub use error::{Error, ExtendedErrorInfo, Result};
|
||||||
pub use js_values::*;
|
pub use js_values::*;
|
||||||
pub use module::Module;
|
pub use module::Module;
|
||||||
pub use status::Status;
|
pub use status::Status;
|
||||||
|
|
|
@ -2,7 +2,7 @@ use futures::prelude::*;
|
||||||
use std::os::raw::{c_char, c_void};
|
use std::os::raw::{c_char, c_void};
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
||||||
use crate::{check_status, sys, Env, NapiValue, Result};
|
use crate::{check_status, sys, Env, JsError, NapiValue, Result};
|
||||||
|
|
||||||
pub struct FuturePromise<T, V: NapiValue> {
|
pub struct FuturePromise<T, V: NapiValue> {
|
||||||
deferred: sys::napi_deferred,
|
deferred: sys::napi_deferred,
|
||||||
|
@ -109,7 +109,8 @@ unsafe extern "C" fn call_js_cb<T, V: NapiValue>(
|
||||||
debug_assert!(status == sys::Status::napi_ok, "Resolve promise failed");
|
debug_assert!(status == sys::Status::napi_ok, "Resolve promise failed");
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
let status = sys::napi_reject_deferred(raw_env, deferred, e.into_raw(raw_env));
|
let status =
|
||||||
|
sys::napi_reject_deferred(raw_env, deferred, JsError::from(e).into_value(raw_env));
|
||||||
debug_assert!(status == sys::Status::napi_ok, "Reject promise failed");
|
debug_assert!(status == sys::Status::napi_ok, "Reject promise failed");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -68,3 +68,33 @@ impl From<i32> for Status {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<Status> for i32 {
|
||||||
|
fn from(code: Status) -> Self {
|
||||||
|
match code {
|
||||||
|
Status::Ok => sys::Status::napi_ok,
|
||||||
|
Status::InvalidArg => sys::Status::napi_invalid_arg,
|
||||||
|
Status::ObjectExpected => sys::Status::napi_object_expected,
|
||||||
|
Status::StringExpected => sys::Status::napi_string_expected,
|
||||||
|
Status::NameExpected => sys::Status::napi_name_expected,
|
||||||
|
Status::FunctionExpected => sys::Status::napi_function_expected,
|
||||||
|
Status::NumberExpected => sys::Status::napi_number_expected,
|
||||||
|
Status::BooleanExpected => sys::Status::napi_boolean_expected,
|
||||||
|
Status::ArrayExpected => sys::Status::napi_array_expected,
|
||||||
|
Status::GenericFailure => sys::Status::napi_generic_failure,
|
||||||
|
Status::PendingException => sys::Status::napi_pending_exception,
|
||||||
|
Status::Cancelled => sys::Status::napi_cancelled,
|
||||||
|
Status::EscapeCalledTwice => sys::Status::napi_escape_called_twice,
|
||||||
|
Status::HandleScopeMismatch => sys::Status::napi_handle_scope_mismatch,
|
||||||
|
Status::CallbackScopeMismatch => sys::Status::napi_callback_scope_mismatch,
|
||||||
|
Status::QueueFull => sys::Status::napi_queue_full,
|
||||||
|
Status::Closing => sys::Status::napi_closing,
|
||||||
|
Status::BigintExpected => sys::Status::napi_bigint_expected,
|
||||||
|
Status::DateExpected => sys::Status::napi_date_expected,
|
||||||
|
Status::ArrayBufferExpected => sys::Status::napi_arraybuffer_expected,
|
||||||
|
Status::DetachableArraybufferExpected => sys::Status::napi_detachable_arraybuffer_expected,
|
||||||
|
Status::WouldDeadlock => sys::Status::napi_would_deadlock,
|
||||||
|
Status::Unknown => sys::Status::napi_generic_failure,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ use std::ptr;
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::{check_status, sys, Env, Error, JsFunction, NapiValue, Result, Status};
|
use crate::{check_status, sys, Env, Error, JsError, JsFunction, NapiValue, Result, Status};
|
||||||
|
|
||||||
use sys::napi_threadsafe_function_call_mode;
|
use sys::napi_threadsafe_function_call_mode;
|
||||||
|
|
||||||
|
@ -291,7 +291,7 @@ unsafe extern "C" fn call_js_cb<T: 'static, V: NapiValue>(
|
||||||
recv,
|
recv,
|
||||||
js_callback,
|
js_callback,
|
||||||
1,
|
1,
|
||||||
[e.into_raw(raw_env)].as_mut_ptr(),
|
[JsError::from(e).into_value(raw_env)].as_mut_ptr(),
|
||||||
ptr::null_mut(),
|
ptr::null_mut(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,6 @@ test('should be able adjust queue size via process.env', async (t) => {
|
||||||
)
|
)
|
||||||
throw new TypeError('Unreachable')
|
throw new TypeError('Unreachable')
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
t.is(e.message, 'QueueFull: Failed to run future: no available capacity')
|
t.snapshot({ code: e.code, message: e.message })
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
14
test_module/__test__/napi4/tokio_rt-isolate.spec.ts.md
Normal file
14
test_module/__test__/napi4/tokio_rt-isolate.spec.ts.md
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
# Snapshot report for `test_module/__test__/napi4/tokio_rt-isolate.spec.ts`
|
||||||
|
|
||||||
|
The actual snapshot is saved in `tokio_rt-isolate.spec.ts.snap`.
|
||||||
|
|
||||||
|
Generated by [AVA](https://avajs.dev).
|
||||||
|
|
||||||
|
## should be able adjust queue size via process.env
|
||||||
|
|
||||||
|
> Snapshot 1
|
||||||
|
|
||||||
|
{
|
||||||
|
code: 'QueueFull',
|
||||||
|
message: 'Failed to run future: no available capacity',
|
||||||
|
}
|
BIN
test_module/__test__/napi4/tokio_rt-isolate.spec.ts.snap
Normal file
BIN
test_module/__test__/napi4/tokio_rt-isolate.spec.ts.snap
Normal file
Binary file not shown.
|
@ -61,6 +61,6 @@ test.serial('should reject if task queue is full', async (t) => {
|
||||||
)
|
)
|
||||||
throw new TypeError('Unreachable')
|
throw new TypeError('Unreachable')
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
t.is(e.message, 'QueueFull: Failed to run future: no available capacity')
|
t.snapshot({ code: e.code, message: e.message })
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
14
test_module/__test__/napi4/tokio_rt.spec.ts.md
Normal file
14
test_module/__test__/napi4/tokio_rt.spec.ts.md
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
# Snapshot report for `test_module/__test__/napi4/tokio_rt.spec.ts`
|
||||||
|
|
||||||
|
The actual snapshot is saved in `tokio_rt.spec.ts.snap`.
|
||||||
|
|
||||||
|
Generated by [AVA](https://avajs.dev).
|
||||||
|
|
||||||
|
## should reject if task queue is full
|
||||||
|
|
||||||
|
> Snapshot 1
|
||||||
|
|
||||||
|
{
|
||||||
|
code: 'QueueFull',
|
||||||
|
message: 'Failed to run future: no available capacity',
|
||||||
|
}
|
BIN
test_module/__test__/napi4/tokio_rt.spec.ts.snap
Normal file
BIN
test_module/__test__/napi4/tokio_rt.spec.ts.snap
Normal file
Binary file not shown.
|
@ -4,17 +4,28 @@ The actual snapshot is saved in `object.spec.ts.snap`.
|
||||||
|
|
||||||
Generated by [AVA](https://avajs.dev).
|
Generated by [AVA](https://avajs.dev).
|
||||||
|
|
||||||
|
## setNamedProperty
|
||||||
|
|
||||||
|
> Snapshot 1
|
||||||
|
|
||||||
|
'RustPropertyKey'
|
||||||
|
|
||||||
## setProperty
|
## setProperty
|
||||||
|
|
||||||
> Snapshot 1
|
> Snapshot 1
|
||||||
|
|
||||||
'Rust object property'
|
'Rust object property'
|
||||||
|
|
||||||
## setNamedProperty
|
## testDeleteElement
|
||||||
|
|
||||||
> Snapshot 1
|
> Snapshot 1
|
||||||
|
|
||||||
'RustPropertyKey'
|
[
|
||||||
|
0,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
3,
|
||||||
|
]
|
||||||
|
|
||||||
## testGetPropertyNames
|
## testGetPropertyNames
|
||||||
|
|
||||||
|
@ -37,14 +48,3 @@ Generated by [AVA](https://avajs.dev).
|
||||||
undefined,
|
undefined,
|
||||||
'foo',
|
'foo',
|
||||||
]
|
]
|
||||||
|
|
||||||
## testDeleteElement
|
|
||||||
|
|
||||||
> Snapshot 1
|
|
||||||
|
|
||||||
[
|
|
||||||
0,
|
|
||||||
undefined,
|
|
||||||
undefined,
|
|
||||||
3,
|
|
||||||
]
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ fn test_throw_with_reason(ctx: CallContext) -> Result<JsUnknown> {
|
||||||
let reason = ctx.get::<JsString>(0)?;
|
let reason = ctx.get::<JsString>(0)?;
|
||||||
Err(Error::new(
|
Err(Error::new(
|
||||||
Status::GenericFailure,
|
Status::GenericFailure,
|
||||||
reason.into_utf8()?.as_str()?.to_owned(),
|
reason.into_utf8()?.into_owned()?,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue