fix(napi): promise resolve error (#1664)
This commit is contained in:
parent
4fdce25a17
commit
a7eeb0c31c
12 changed files with 212 additions and 214 deletions
16
.github/workflows/test-release.yaml
vendored
16
.github/workflows/test-release.yaml
vendored
|
@ -124,7 +124,7 @@ jobs:
|
||||||
- settings:
|
- settings:
|
||||||
target: i686-pc-windows-msvc
|
target: i686-pc-windows-msvc
|
||||||
node: 18
|
node: 18
|
||||||
name: stable - ${{ matrix.settings.host }} - node@${{ matrix.node }}
|
name: ${{ matrix.settings.host }} - node@${{ matrix.node }} - toolchain@ ${{ matrix.settings.toolchain }}
|
||||||
runs-on: ${{ matrix.settings.host }}
|
runs-on: ${{ matrix.settings.host }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
@ -292,6 +292,8 @@ jobs:
|
||||||
options: -v ${{ github.workspace }}/.cargo-cache/registry:/usr/local/cargo/registry -v ${{ github.workspace }}/.cargo-cache/git:/usr/local/cargo/git -v ${{ github.workspace }}:/napi-rs -w /napi-rs
|
options: -v ${{ github.workspace }}/.cargo-cache/registry:/usr/local/cargo/registry -v ${{ github.workspace }}/.cargo-cache/git:/usr/local/cargo/git -v ${{ github.workspace }}:/napi-rs -w /napi-rs
|
||||||
run: |
|
run: |
|
||||||
yarn build:test -- --target ${{ matrix.settings.target }}
|
yarn build:test -- --target ${{ matrix.settings.target }}
|
||||||
|
chmod 777 -R .cargo-cache
|
||||||
|
chmod 777 -R target
|
||||||
|
|
||||||
- uses: actions/upload-artifact@v3
|
- uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
|
@ -365,8 +367,16 @@ jobs:
|
||||||
uses: addnab/docker-run-action@v3
|
uses: addnab/docker-run-action@v3
|
||||||
with:
|
with:
|
||||||
image: ${{ steps.image-name.outputs.docker-image }}
|
image: ${{ steps.image-name.outputs.docker-image }}
|
||||||
options: ${{ matrix.settings.args }} -v ${{ github.workspace }}:/build -w /build
|
options: ${{ matrix.settings.args }} -v ${{ github.workspace }}/cores:/cores -v ${{ github.workspace }}:/build -w /build
|
||||||
run: yarn test
|
run: >-
|
||||||
|
ulimit -c &&
|
||||||
|
ulimit -c unlimited &&
|
||||||
|
ulimit -c &&
|
||||||
|
yarn test
|
||||||
|
- name: List files
|
||||||
|
run: |
|
||||||
|
ls -la .
|
||||||
|
ls -la ./cores
|
||||||
|
|
||||||
build-and-test-linux-armv7:
|
build-and-test-linux-armv7:
|
||||||
name: stable - armv7-unknown-linux-gnu - node@18
|
name: stable - armv7-unknown-linux-gnu - node@18
|
||||||
|
|
|
@ -72,11 +72,8 @@ pub fn run<T: Task>(
|
||||||
env,
|
env,
|
||||||
raw_resource,
|
raw_resource,
|
||||||
async_work_name,
|
async_work_name,
|
||||||
Some(execute::<T> as unsafe extern "C" fn(env: sys::napi_env, data: *mut c_void)),
|
Some(execute::<T>),
|
||||||
Some(
|
Some(complete::<T>),
|
||||||
complete::<T>
|
|
||||||
as unsafe extern "C" fn(env: sys::napi_env, status: sys::napi_status, data: *mut c_void),
|
|
||||||
),
|
|
||||||
(result as *mut AsyncWork<T>).cast(),
|
(result as *mut AsyncWork<T>).cast(),
|
||||||
&mut result.napi_async_work,
|
&mut result.napi_async_work,
|
||||||
)
|
)
|
||||||
|
|
|
@ -81,7 +81,10 @@ impl<T: FromNapiValue> ValidateNapiValue for Promise<T> {
|
||||||
unsafe { crate::sys::napi_create_error(env, code, message, &mut err) },
|
unsafe { crate::sys::napi_create_error(env, code, message, &mut err) },
|
||||||
"Failed to create rejected error"
|
"Failed to create rejected error"
|
||||||
)?;
|
)?;
|
||||||
check_status!(unsafe { crate::sys::napi_reject_deferred(env, deferred, err) })?;
|
check_status!(
|
||||||
|
unsafe { crate::sys::napi_reject_deferred(env, deferred, err) },
|
||||||
|
"Failed to reject promise in validate"
|
||||||
|
)?;
|
||||||
return Ok(promise);
|
return Ok(promise);
|
||||||
}
|
}
|
||||||
Ok(ptr::null_mut())
|
Ok(ptr::null_mut())
|
||||||
|
|
|
@ -18,7 +18,7 @@ impl TypeName for String {
|
||||||
|
|
||||||
impl ValidateNapiValue for String {}
|
impl ValidateNapiValue for String {}
|
||||||
|
|
||||||
impl ToNapiValue for String {
|
impl ToNapiValue for &String {
|
||||||
unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
|
unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
|
||||||
let mut ptr = ptr::null_mut();
|
let mut ptr = ptr::null_mut();
|
||||||
|
|
||||||
|
@ -31,6 +31,16 @@ impl ToNapiValue for String {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ToNapiValue for String {
|
||||||
|
#[inline]
|
||||||
|
unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
|
||||||
|
#[allow(clippy::needless_borrow)]
|
||||||
|
unsafe {
|
||||||
|
ToNapiValue::to_napi_value(env, &val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl FromNapiValue for String {
|
impl FromNapiValue for String {
|
||||||
unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
|
unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
|
||||||
let mut len = 0;
|
let mut len = 0;
|
||||||
|
|
|
@ -159,5 +159,5 @@ unsafe extern "C" fn async_task_abort_controller_finalize(
|
||||||
finalize_data: *mut c_void,
|
finalize_data: *mut c_void,
|
||||||
_finalize_hint: *mut c_void,
|
_finalize_hint: *mut c_void,
|
||||||
) {
|
) {
|
||||||
unsafe { Box::from_raw(finalize_data as *mut AbortSignal) };
|
drop(unsafe { Box::from_raw(finalize_data as *mut AbortSignal) });
|
||||||
}
|
}
|
||||||
|
|
|
@ -268,7 +268,7 @@ impl<T: 'static, S: 'static> SharedReference<T, S> {
|
||||||
let raw = Box::into_raw(Box::new(s));
|
let raw = Box::into_raw(Box::new(s));
|
||||||
let prev_drop_fn = unsafe { Box::from_raw(self.owner.finalize_callbacks.get()) };
|
let prev_drop_fn = unsafe { Box::from_raw(self.owner.finalize_callbacks.get()) };
|
||||||
let drop_fn = Box::new(move || {
|
let drop_fn = Box::new(move || {
|
||||||
unsafe { Box::from_raw(raw) };
|
drop(unsafe { Box::from_raw(raw) });
|
||||||
prev_drop_fn();
|
prev_drop_fn();
|
||||||
});
|
});
|
||||||
self.owner.finalize_callbacks.set(Box::into_raw(drop_fn));
|
self.owner.finalize_callbacks.set(Box::into_raw(drop_fn));
|
||||||
|
|
|
@ -8,7 +8,7 @@ use std::os::raw::{c_char, c_void};
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
||||||
use crate::bindgen_runtime::FromNapiValue;
|
use crate::bindgen_runtime::FromNapiValue;
|
||||||
#[cfg(all(feature = "napi4"))]
|
#[cfg(feature = "napi4")]
|
||||||
use crate::bindgen_runtime::ToNapiValue;
|
use crate::bindgen_runtime::ToNapiValue;
|
||||||
use crate::{
|
use crate::{
|
||||||
async_work::{self, AsyncWorkPromise},
|
async_work::{self, AsyncWorkPromise},
|
||||||
|
@ -23,15 +23,15 @@ use crate::{
|
||||||
use crate::async_cleanup_hook::AsyncCleanupHook;
|
use crate::async_cleanup_hook::AsyncCleanupHook;
|
||||||
#[cfg(feature = "napi3")]
|
#[cfg(feature = "napi3")]
|
||||||
use crate::cleanup_env::{CleanupEnvHook, CleanupEnvHookData};
|
use crate::cleanup_env::{CleanupEnvHook, CleanupEnvHookData};
|
||||||
#[cfg(all(feature = "serde-json"))]
|
#[cfg(feature = "serde-json")]
|
||||||
use crate::js_values::{De, Ser};
|
use crate::js_values::{De, Ser};
|
||||||
#[cfg(feature = "napi4")]
|
#[cfg(feature = "napi4")]
|
||||||
use crate::threadsafe_function::{ThreadSafeCallContext, ThreadsafeFunction};
|
use crate::threadsafe_function::{ThreadSafeCallContext, ThreadsafeFunction};
|
||||||
#[cfg(feature = "napi3")]
|
#[cfg(feature = "napi3")]
|
||||||
use crate::JsError;
|
use crate::JsError;
|
||||||
#[cfg(all(feature = "serde-json"))]
|
#[cfg(feature = "serde-json")]
|
||||||
use serde::de::DeserializeOwned;
|
use serde::de::DeserializeOwned;
|
||||||
#[cfg(all(feature = "serde-json"))]
|
#[cfg(feature = "serde-json")]
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
pub type Callback = unsafe extern "C" fn(sys::napi_env, sys::napi_callback_info) -> sys::napi_value;
|
pub type Callback = unsafe extern "C" fn(sys::napi_env, sys::napi_callback_info) -> sys::napi_value;
|
||||||
|
@ -1345,7 +1345,7 @@ pub(crate) unsafe extern "C" fn raw_finalize<T>(
|
||||||
finalize_hint: *mut c_void,
|
finalize_hint: *mut c_void,
|
||||||
) {
|
) {
|
||||||
let tagged_object = finalize_data as *mut TaggedObject<T>;
|
let tagged_object = finalize_data as *mut TaggedObject<T>;
|
||||||
unsafe { Box::from_raw(tagged_object) };
|
drop(unsafe { Box::from_raw(tagged_object) });
|
||||||
if !finalize_hint.is_null() {
|
if !finalize_hint.is_null() {
|
||||||
let size_hint = unsafe { *Box::from_raw(finalize_hint as *mut Option<i64>) };
|
let size_hint = unsafe { *Box::from_raw(finalize_hint as *mut Option<i64>) };
|
||||||
if let Some(changed) = size_hint {
|
if let Some(changed) = size_hint {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::convert::{From, TryFrom};
|
use std::convert::{From, TryFrom};
|
||||||
use std::error;
|
use std::error;
|
||||||
use std::ffi::{CStr, CString};
|
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;
|
||||||
|
@ -25,8 +25,7 @@ pub struct Error<S: AsRef<str> = Status> {
|
||||||
pub status: S,
|
pub status: S,
|
||||||
pub reason: String,
|
pub reason: String,
|
||||||
// Convert raw `JsError` into Error
|
// Convert raw `JsError` into Error
|
||||||
maybe_raw: sys::napi_ref,
|
pub(crate) maybe_raw: sys::napi_ref,
|
||||||
maybe_env: sys::napi_env,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: AsRef<str>> ToNapiValue for Error<S> {
|
impl<S: AsRef<str>> ToNapiValue for Error<S> {
|
||||||
|
@ -36,9 +35,14 @@ impl<S: AsRef<str>> ToNapiValue for Error<S> {
|
||||||
Ok(err)
|
Ok(err)
|
||||||
} else {
|
} else {
|
||||||
let mut value = std::ptr::null_mut();
|
let mut value = std::ptr::null_mut();
|
||||||
check_status!(unsafe {
|
check_status!(
|
||||||
sys::napi_get_reference_value(val.maybe_env, val.maybe_raw, &mut value)
|
unsafe { sys::napi_get_reference_value(env, val.maybe_raw, &mut value) },
|
||||||
})?;
|
"Get error reference in `to_napi_value` failed"
|
||||||
|
)?;
|
||||||
|
check_status!(
|
||||||
|
unsafe { sys::napi_delete_reference(env, val.maybe_raw) },
|
||||||
|
"Delete error reference in `to_napi_value` failed"
|
||||||
|
)?;
|
||||||
Ok(value)
|
Ok(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -79,7 +83,7 @@ impl From<SerdeJSONError> for Error {
|
||||||
impl From<JsUnknown> for Error {
|
impl From<JsUnknown> for Error {
|
||||||
fn from(value: JsUnknown) -> Self {
|
fn from(value: JsUnknown) -> Self {
|
||||||
let mut result = std::ptr::null_mut();
|
let mut result = std::ptr::null_mut();
|
||||||
let status = unsafe { sys::napi_create_reference(value.0.env, value.0.value, 0, &mut result) };
|
let status = unsafe { sys::napi_create_reference(value.0.env, value.0.value, 1, &mut result) };
|
||||||
if status != sys::Status::napi_ok {
|
if status != sys::Status::napi_ok {
|
||||||
return Error::new(
|
return Error::new(
|
||||||
Status::from(status),
|
Status::from(status),
|
||||||
|
@ -90,7 +94,6 @@ impl From<JsUnknown> for Error {
|
||||||
status: Status::GenericFailure,
|
status: Status::GenericFailure,
|
||||||
reason: "".to_string(),
|
reason: "".to_string(),
|
||||||
maybe_raw: result,
|
maybe_raw: result,
|
||||||
maybe_env: value.0.env,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -118,7 +121,6 @@ impl<S: AsRef<str>> Error<S> {
|
||||||
status,
|
status,
|
||||||
reason: reason.to_string(),
|
reason: reason.to_string(),
|
||||||
maybe_raw: ptr::null_mut(),
|
maybe_raw: ptr::null_mut(),
|
||||||
maybe_env: ptr::null_mut(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,7 +129,6 @@ impl<S: AsRef<str>> Error<S> {
|
||||||
status,
|
status,
|
||||||
reason: "".to_owned(),
|
reason: "".to_owned(),
|
||||||
maybe_raw: ptr::null_mut(),
|
maybe_raw: ptr::null_mut(),
|
||||||
maybe_env: ptr::null_mut(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -138,7 +139,6 @@ impl Error {
|
||||||
status: Status::GenericFailure,
|
status: Status::GenericFailure,
|
||||||
reason: reason.into(),
|
reason: reason.into(),
|
||||||
maybe_raw: ptr::null_mut(),
|
maybe_raw: ptr::null_mut(),
|
||||||
maybe_env: ptr::null_mut(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -149,7 +149,6 @@ impl From<std::ffi::NulError> for Error {
|
||||||
status: Status::GenericFailure,
|
status: Status::GenericFailure,
|
||||||
reason: format!("{}", error),
|
reason: format!("{}", error),
|
||||||
maybe_raw: ptr::null_mut(),
|
maybe_raw: ptr::null_mut(),
|
||||||
maybe_env: ptr::null_mut(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -160,23 +159,6 @@ impl From<std::io::Error> for Error {
|
||||||
status: Status::GenericFailure,
|
status: Status::GenericFailure,
|
||||||
reason: format!("{}", error),
|
reason: format!("{}", error),
|
||||||
maybe_raw: ptr::null_mut(),
|
maybe_raw: ptr::null_mut(),
|
||||||
maybe_env: ptr::null_mut(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S: AsRef<str>> Drop for Error<S> {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
#[cfg(not(feature = "noop"))]
|
|
||||||
{
|
|
||||||
if !self.maybe_env.is_null() && !self.maybe_raw.is_null() {
|
|
||||||
let delete_reference_status =
|
|
||||||
unsafe { sys::napi_delete_reference(self.maybe_env, self.maybe_raw) };
|
|
||||||
debug_assert!(
|
|
||||||
delete_reference_status == sys::Status::napi_ok,
|
|
||||||
"Delete Error Reference failed"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -237,6 +219,11 @@ macro_rules! impl_object_methods {
|
||||||
get_err_status == sys::Status::napi_ok,
|
get_err_status == sys::Status::napi_ok,
|
||||||
"Get Error from Reference failed"
|
"Get Error from Reference failed"
|
||||||
);
|
);
|
||||||
|
let delete_err_status = unsafe { sys::napi_delete_reference(env, self.0.maybe_raw) };
|
||||||
|
debug_assert!(
|
||||||
|
delete_err_status == sys::Status::napi_ok,
|
||||||
|
"Delete Error Reference failed"
|
||||||
|
);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,28 +276,6 @@ macro_rules! impl_object_methods {
|
||||||
status
|
status
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::not_unsafe_ptr_arg_deref)]
|
|
||||||
pub fn throw(&self, env: sys::napi_env) -> Result<()> {
|
|
||||||
let error_status = format!("{:?}\0", self.0.status.as_ref());
|
|
||||||
let status_len = error_status.len();
|
|
||||||
let error_code_string =
|
|
||||||
unsafe { CStr::from_bytes_with_nul_unchecked(error_status.as_bytes()) };
|
|
||||||
let reason_len = self.0.reason.len();
|
|
||||||
let reason_c_string = format!("{}\0", self.0.reason.clone());
|
|
||||||
let reason = unsafe { CStr::from_bytes_with_nul_unchecked(reason_c_string.as_bytes()) };
|
|
||||||
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, error_code_string.as_ptr(), status_len, &mut error_code)
|
|
||||||
})?;
|
|
||||||
check_status!(unsafe {
|
|
||||||
sys::napi_create_string_utf8(env, reason.as_ptr(), reason_len, &mut reason_string)
|
|
||||||
})?;
|
|
||||||
check_status!(unsafe { $kind(env, error_code, reason_string, &mut js_error) })?;
|
|
||||||
check_status!(unsafe { sys::napi_throw(env, js_error) })
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: AsRef<str>> From<Error<S>> for $js_value<S> {
|
impl<S: AsRef<str>> From<Error<S>> for $js_value<S> {
|
||||||
|
|
|
@ -4,8 +4,6 @@ use std::os::raw::c_void;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
||||||
use crate::bindgen_runtime::{ToNapiValue, THREAD_DESTROYED};
|
use crate::bindgen_runtime::{ToNapiValue, THREAD_DESTROYED};
|
||||||
#[cfg(feature = "deferred_trace")]
|
|
||||||
use crate::JsError;
|
|
||||||
use crate::{check_status, JsObject, Value};
|
use crate::{check_status, JsObject, Value};
|
||||||
use crate::{sys, Env, Error, Result};
|
use crate::{sys, Env, Error, Result};
|
||||||
#[cfg(feature = "deferred_trace")]
|
#[cfg(feature = "deferred_trace")]
|
||||||
|
@ -19,92 +17,73 @@ use crate::{NapiRaw, NapiValue};
|
||||||
///
|
///
|
||||||
/// See this issue for more details:
|
/// See this issue for more details:
|
||||||
/// https://github.com/nodejs/node-addon-api/issues/595
|
/// https://github.com/nodejs/node-addon-api/issues/595
|
||||||
struct DeferredTrace {
|
#[repr(transparent)]
|
||||||
value: sys::napi_ref,
|
struct DeferredTrace(sys::napi_ref);
|
||||||
#[cfg(not(feature = "noop"))]
|
|
||||||
env: sys::napi_env,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "deferred_trace")]
|
#[cfg(feature = "deferred_trace")]
|
||||||
impl DeferredTrace {
|
impl DeferredTrace {
|
||||||
fn new(raw_env: sys::napi_env) -> Self {
|
fn new(raw_env: sys::napi_env) -> Result<Self> {
|
||||||
let env = unsafe { Env::from_raw(raw_env) };
|
let env = unsafe { Env::from_raw(raw_env) };
|
||||||
let reason = env.create_string("none").unwrap();
|
let reason = env.create_string("none").unwrap();
|
||||||
|
|
||||||
let mut js_error = ptr::null_mut();
|
let mut js_error = ptr::null_mut();
|
||||||
let create_error_status =
|
check_status!(
|
||||||
unsafe { sys::napi_create_error(raw_env, ptr::null_mut(), reason.raw(), &mut js_error) };
|
unsafe { sys::napi_create_error(raw_env, ptr::null_mut(), reason.raw(), &mut js_error) },
|
||||||
debug_assert!(create_error_status == sys::Status::napi_ok);
|
"Create error in DeferredTrace failed"
|
||||||
|
)?;
|
||||||
|
|
||||||
let mut result = ptr::null_mut();
|
let mut result = ptr::null_mut();
|
||||||
let status = unsafe { sys::napi_create_reference(raw_env, js_error, 1, &mut result) };
|
check_status!(
|
||||||
debug_assert!(status == sys::Status::napi_ok);
|
unsafe { sys::napi_create_reference(raw_env, js_error, 1, &mut result) },
|
||||||
|
"Create reference in DeferredTrace failed"
|
||||||
|
)?;
|
||||||
|
|
||||||
Self {
|
Ok(Self(result))
|
||||||
value: result,
|
|
||||||
#[cfg(not(feature = "noop"))]
|
|
||||||
env: raw_env,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn into_rejected(self, raw_env: sys::napi_env, err: Error) -> Result<sys::napi_value> {
|
fn into_rejected(self, raw_env: sys::napi_env, err: Error) -> Result<sys::napi_value> {
|
||||||
let env = unsafe { Env::from_raw(raw_env) };
|
let env = unsafe { Env::from_raw(raw_env) };
|
||||||
let raw = unsafe { DeferredTrace::to_napi_value(raw_env, self)? };
|
let mut raw = ptr::null_mut();
|
||||||
|
check_status!(
|
||||||
|
unsafe { sys::napi_get_reference_value(raw_env, self.0, &mut raw) },
|
||||||
|
"Failed to get referenced value in DeferredTrace"
|
||||||
|
)?;
|
||||||
|
|
||||||
let mut obj = unsafe { JsObject::from_raw(raw_env, raw)? };
|
let mut obj = unsafe { JsObject::from_raw_unchecked(raw_env, raw) };
|
||||||
if err.reason.is_empty() && err.status == crate::Status::GenericFailure {
|
let err_value = if !err.maybe_raw.is_null() {
|
||||||
// Can't clone err as the clone containing napi pointers will
|
let mut err_raw_value = std::ptr::null_mut();
|
||||||
// be freed when this function returns, causing err to be freed twice.
|
check_status!(
|
||||||
// Someone should probably fix this.
|
unsafe { sys::napi_get_reference_value(raw_env, err.maybe_raw, &mut err_raw_value) },
|
||||||
let err_obj = JsError::from(err).into_unknown(env).coerce_to_object()?;
|
"Get error reference in `to_napi_value` failed"
|
||||||
|
)?;
|
||||||
|
let err_obj = unsafe { JsObject::from_raw_unchecked(raw_env, err_raw_value) };
|
||||||
|
|
||||||
if err_obj.has_named_property("message")? {
|
let err_value = if err_obj.has_named_property("message")? {
|
||||||
// The error was already created inside the JS engine, just return it
|
// The error was already created inside the JS engine, just return it
|
||||||
Ok(unsafe { JsError::from(Error::from(err_obj.into_unknown())).into_value(raw_env) })
|
Ok(unsafe { err_obj.raw() })
|
||||||
} else {
|
} else {
|
||||||
obj.set_named_property("message", "")?;
|
obj.set_named_property("message", "")?;
|
||||||
obj.set_named_property("code", "")?;
|
obj.set_named_property("code", "")?;
|
||||||
Ok(raw)
|
Ok(raw)
|
||||||
}
|
};
|
||||||
|
check_status!(
|
||||||
|
unsafe { sys::napi_delete_reference(raw_env, err.maybe_raw) },
|
||||||
|
"Delete error reference in `to_napi_value` failed"
|
||||||
|
)?;
|
||||||
|
err_value
|
||||||
} else {
|
} else {
|
||||||
obj.set_named_property("message", env.create_string(&err.reason)?)?;
|
obj.set_named_property("message", &err.reason)?;
|
||||||
obj.set_named_property("code", env.create_string_from_std(err.status.to_string())?)?;
|
obj.set_named_property(
|
||||||
|
"code",
|
||||||
|
env.create_string_from_std(format!("{}", err.status))?,
|
||||||
|
)?;
|
||||||
Ok(raw)
|
Ok(raw)
|
||||||
}
|
};
|
||||||
}
|
check_status!(
|
||||||
}
|
unsafe { sys::napi_delete_reference(raw_env, self.0) },
|
||||||
|
"Failed to get referenced value in DeferredTrace"
|
||||||
#[cfg(feature = "deferred_trace")]
|
)?;
|
||||||
impl ToNapiValue for DeferredTrace {
|
err_value
|
||||||
unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
|
|
||||||
let mut value = ptr::null_mut();
|
|
||||||
check_status!(unsafe { sys::napi_get_reference_value(env, val.value, &mut value) })?;
|
|
||||||
|
|
||||||
if value.is_null() {
|
|
||||||
// This shouldn't happen but a panic is better than a segfault
|
|
||||||
Err(Error::new(
|
|
||||||
crate::Status::GenericFailure,
|
|
||||||
"Failed to get deferred error reference",
|
|
||||||
))
|
|
||||||
} else {
|
|
||||||
Ok(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "deferred_trace")]
|
|
||||||
impl Drop for DeferredTrace {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
#[cfg(not(feature = "noop"))]
|
|
||||||
{
|
|
||||||
if !self.env.is_null() && !self.value.is_null() {
|
|
||||||
let delete_reference_status = unsafe { sys::napi_delete_reference(self.env, self.value) };
|
|
||||||
debug_assert!(
|
|
||||||
delete_reference_status == sys::Status::napi_ok,
|
|
||||||
"Delete Error Reference failed"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,31 +117,35 @@ impl<Data: ToNapiValue, Resolver: FnOnce(Env) -> Result<Data>> JsDeferred<Data,
|
||||||
// Create a threadsafe function so we can call back into the JS thread when we are done.
|
// Create a threadsafe function so we can call back into the JS thread when we are done.
|
||||||
let mut async_resource_name = ptr::null_mut();
|
let mut async_resource_name = ptr::null_mut();
|
||||||
let s = unsafe { CStr::from_bytes_with_nul_unchecked(b"napi_resolve_deferred\0") };
|
let s = unsafe { CStr::from_bytes_with_nul_unchecked(b"napi_resolve_deferred\0") };
|
||||||
check_status!(unsafe {
|
check_status!(
|
||||||
sys::napi_create_string_utf8(env, s.as_ptr(), 22, &mut async_resource_name)
|
unsafe { sys::napi_create_string_utf8(env, s.as_ptr(), 22, &mut async_resource_name) },
|
||||||
})?;
|
"Create async resource name in JsDeferred failed"
|
||||||
|
)?;
|
||||||
|
|
||||||
let mut tsfn = ptr::null_mut();
|
let mut tsfn = ptr::null_mut();
|
||||||
check_status! {unsafe {
|
check_status!(
|
||||||
sys::napi_create_threadsafe_function(
|
unsafe {
|
||||||
env,
|
sys::napi_create_threadsafe_function(
|
||||||
ptr::null_mut(),
|
env,
|
||||||
ptr::null_mut(),
|
ptr::null_mut(),
|
||||||
async_resource_name,
|
ptr::null_mut(),
|
||||||
0,
|
async_resource_name,
|
||||||
1,
|
0,
|
||||||
ptr::null_mut(),
|
1,
|
||||||
None,
|
ptr::null_mut(),
|
||||||
raw_deferred as *mut c_void,
|
None,
|
||||||
Some(napi_resolve_deferred::<Data, Resolver>),
|
raw_deferred.cast(),
|
||||||
&mut tsfn,
|
Some(napi_resolve_deferred::<Data, Resolver>),
|
||||||
)
|
&mut tsfn,
|
||||||
}}?;
|
)
|
||||||
|
},
|
||||||
|
"Create threadsafe function in JsDeferred failed"
|
||||||
|
)?;
|
||||||
|
|
||||||
let deferred = Self {
|
let deferred = Self {
|
||||||
tsfn,
|
tsfn,
|
||||||
#[cfg(feature = "deferred_trace")]
|
#[cfg(feature = "deferred_trace")]
|
||||||
trace: DeferredTrace::new(env),
|
trace: DeferredTrace::new(env)?,
|
||||||
_data: PhantomData,
|
_data: PhantomData,
|
||||||
_resolver: PhantomData,
|
_resolver: PhantomData,
|
||||||
};
|
};
|
||||||
|
@ -198,13 +181,13 @@ impl<Data: ToNapiValue, Resolver: FnOnce(Env) -> Result<Data>> JsDeferred<Data,
|
||||||
let status = unsafe {
|
let status = unsafe {
|
||||||
sys::napi_call_threadsafe_function(
|
sys::napi_call_threadsafe_function(
|
||||||
self.tsfn,
|
self.tsfn,
|
||||||
Box::into_raw(Box::from(data)) as *mut c_void,
|
Box::into_raw(Box::from(data)).cast(),
|
||||||
sys::ThreadsafeFunctionCallMode::nonblocking,
|
sys::ThreadsafeFunctionCallMode::blocking,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
status == sys::Status::napi_ok,
|
status == sys::Status::napi_ok,
|
||||||
"Call threadsafe function failed"
|
"Call threadsafe function in JsDeferred failed"
|
||||||
);
|
);
|
||||||
|
|
||||||
let status = unsafe {
|
let status = unsafe {
|
||||||
|
@ -212,7 +195,7 @@ impl<Data: ToNapiValue, Resolver: FnOnce(Env) -> Result<Data>> JsDeferred<Data,
|
||||||
};
|
};
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
status == sys::Status::napi_ok,
|
status == sys::Status::napi_ok,
|
||||||
"Release threadsafe function failed"
|
"Release threadsafe function in JsDeferred failed"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -229,34 +212,46 @@ extern "C" fn napi_resolve_deferred<Data: ToNapiValue, Resolver: FnOnce(Env) ->
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let deferred = context as sys::napi_deferred;
|
let deferred = context.cast();
|
||||||
let deferred_data = unsafe { Box::from_raw(data as *mut DeferredData<Data, Resolver>) };
|
let deferred_data: Box<DeferredData<Data, Resolver>> = unsafe { Box::from_raw(data.cast()) };
|
||||||
let result = deferred_data
|
let result = deferred_data
|
||||||
.resolver
|
.resolver
|
||||||
.and_then(|resolver| resolver(unsafe { Env::from_raw(env) }))
|
.and_then(|resolver| resolver(unsafe { Env::from_raw(env) }))
|
||||||
.and_then(|res| unsafe { ToNapiValue::to_napi_value(env, res) });
|
.and_then(|res| unsafe { ToNapiValue::to_napi_value(env, res) });
|
||||||
|
|
||||||
match result {
|
if let Err(e) = result.and_then(|res| {
|
||||||
Ok(res) => {
|
check_status!(
|
||||||
let status = unsafe { sys::napi_resolve_deferred(env, deferred, res) };
|
unsafe { sys::napi_resolve_deferred(env, deferred, res) },
|
||||||
debug_assert!(
|
"Resolve deferred value failed"
|
||||||
status == sys::Status::napi_ok,
|
)
|
||||||
"Resolve promise failed {:?}",
|
}) {
|
||||||
crate::Status::from(status)
|
#[cfg(feature = "deferred_trace")]
|
||||||
);
|
let error = deferred_data.trace.into_rejected(env, e);
|
||||||
}
|
#[cfg(not(feature = "deferred_trace"))]
|
||||||
Err(e) => {
|
let error = Ok::<sys::napi_value, Error>(unsafe { crate::JsError::from(e).into_value(env) });
|
||||||
#[cfg(feature = "deferred_trace")]
|
|
||||||
let error = deferred_data.trace.into_rejected(env, e).unwrap();
|
|
||||||
#[cfg(not(feature = "deferred_trace"))]
|
|
||||||
let error = unsafe { crate::JsError::from(e).into_value(env) };
|
|
||||||
|
|
||||||
let status = unsafe { sys::napi_reject_deferred(env, deferred, error) };
|
match error {
|
||||||
debug_assert!(
|
Ok(error) => {
|
||||||
status == sys::Status::napi_ok,
|
unsafe { sys::napi_reject_deferred(env, deferred, error) };
|
||||||
"Reject promise failed {:?}",
|
}
|
||||||
crate::Status::from(status)
|
Err(err) => {
|
||||||
);
|
#[cfg(debug_assertions)]
|
||||||
|
{
|
||||||
|
println!("Failed to reject deferred: {:?}", err);
|
||||||
|
let mut err = ptr::null_mut();
|
||||||
|
let mut err_msg = ptr::null_mut();
|
||||||
|
unsafe {
|
||||||
|
sys::napi_create_string_utf8(
|
||||||
|
env,
|
||||||
|
"Rejection failed\0".as_ptr().cast(),
|
||||||
|
0,
|
||||||
|
&mut err_msg,
|
||||||
|
);
|
||||||
|
sys::napi_create_error(env, ptr::null_mut(), err_msg, &mut err);
|
||||||
|
sys::napi_reject_deferred(env, deferred, err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -337,9 +337,12 @@ macro_rules! impl_object_methods {
|
||||||
&mut js_function,
|
&mut js_function,
|
||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
check_status!(unsafe {
|
check_status!(
|
||||||
sys::napi_set_named_property(self.0.env, self.0.value, name.as_ptr(), js_function)
|
unsafe {
|
||||||
})
|
sys::napi_set_named_property(self.0.env, self.0.value, name.as_ptr(), js_function)
|
||||||
|
},
|
||||||
|
"create_named_method error"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_named_property<T>(&self, name: &str) -> Result<T>
|
pub fn get_named_property<T>(&self, name: &str) -> Result<T>
|
||||||
|
@ -348,9 +351,12 @@ macro_rules! impl_object_methods {
|
||||||
{
|
{
|
||||||
let key = CString::new(name)?;
|
let key = CString::new(name)?;
|
||||||
let mut raw_value = ptr::null_mut();
|
let mut raw_value = ptr::null_mut();
|
||||||
check_status!(unsafe {
|
check_status!(
|
||||||
sys::napi_get_named_property(self.0.env, self.0.value, key.as_ptr(), &mut raw_value)
|
unsafe {
|
||||||
})?;
|
sys::napi_get_named_property(self.0.env, self.0.value, key.as_ptr(), &mut raw_value)
|
||||||
|
},
|
||||||
|
"get_named_property error"
|
||||||
|
)?;
|
||||||
unsafe { <T as FromNapiValue>::from_napi_value(self.0.env, raw_value) }
|
unsafe { <T as FromNapiValue>::from_napi_value(self.0.env, raw_value) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -360,18 +366,24 @@ macro_rules! impl_object_methods {
|
||||||
{
|
{
|
||||||
let key = CString::new(name)?;
|
let key = CString::new(name)?;
|
||||||
let mut raw_value = ptr::null_mut();
|
let mut raw_value = ptr::null_mut();
|
||||||
check_status!(unsafe {
|
check_status!(
|
||||||
sys::napi_get_named_property(self.0.env, self.0.value, key.as_ptr(), &mut raw_value)
|
unsafe {
|
||||||
})?;
|
sys::napi_get_named_property(self.0.env, self.0.value, key.as_ptr(), &mut raw_value)
|
||||||
|
},
|
||||||
|
"get_named_property_unchecked error"
|
||||||
|
)?;
|
||||||
unsafe { <T as FromNapiValue>::from_napi_value(self.0.env, raw_value) }
|
unsafe { <T as FromNapiValue>::from_napi_value(self.0.env, raw_value) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn has_named_property(&self, name: &str) -> Result<bool> {
|
pub fn has_named_property<N: AsRef<str>>(&self, name: N) -> Result<bool> {
|
||||||
let mut result = false;
|
let mut result = false;
|
||||||
let key = CString::new(name)?;
|
let key = CString::new(name.as_ref())?;
|
||||||
check_status!(unsafe {
|
check_status!(
|
||||||
sys::napi_has_named_property(self.0.env, self.0.value, key.as_ptr(), &mut result)
|
unsafe {
|
||||||
})?;
|
sys::napi_has_named_property(self.0.env, self.0.value, key.as_ptr(), &mut result)
|
||||||
|
},
|
||||||
|
"napi_has_named_property error"
|
||||||
|
)?;
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -488,26 +488,29 @@ impl<T: 'static> ThreadsafeFunction<T, ErrorStrategy::CalleeHandled> {
|
||||||
return Err(crate::Error::from_status(Status::Closing));
|
return Err(crate::Error::from_status(Status::Closing));
|
||||||
}
|
}
|
||||||
|
|
||||||
check_status!(unsafe {
|
check_status!(
|
||||||
sys::napi_call_threadsafe_function(
|
unsafe {
|
||||||
self.handle.get_raw(),
|
sys::napi_call_threadsafe_function(
|
||||||
Box::into_raw(Box::new(value.map(|data| {
|
self.handle.get_raw(),
|
||||||
ThreadsafeFunctionCallJsBackData {
|
Box::into_raw(Box::new(value.map(|data| {
|
||||||
data,
|
ThreadsafeFunctionCallJsBackData {
|
||||||
call_variant: ThreadsafeFunctionCallVariant::WithCallback,
|
data,
|
||||||
callback: Box::new(move |d: Result<JsUnknown>| {
|
call_variant: ThreadsafeFunctionCallVariant::WithCallback,
|
||||||
sender
|
callback: Box::new(move |d: Result<JsUnknown>| {
|
||||||
.send(d.and_then(|d| D::from_napi_value(d.0.env, d.0.value)))
|
sender
|
||||||
.map_err(|_| {
|
.send(d.and_then(|d| D::from_napi_value(d.0.env, d.0.value)))
|
||||||
crate::Error::from_reason("Failed to send return value to tokio sender")
|
.map_err(|_| {
|
||||||
})
|
crate::Error::from_reason("Failed to send return value to tokio sender")
|
||||||
}),
|
})
|
||||||
}
|
}),
|
||||||
})))
|
}
|
||||||
.cast(),
|
})))
|
||||||
ThreadsafeFunctionCallMode::NonBlocking.into(),
|
.cast(),
|
||||||
)
|
ThreadsafeFunctionCallMode::NonBlocking.into(),
|
||||||
})
|
)
|
||||||
|
},
|
||||||
|
"Threadsafe function call_async failed"
|
||||||
|
)
|
||||||
})?;
|
})?;
|
||||||
receiver
|
receiver
|
||||||
.await
|
.await
|
||||||
|
@ -741,11 +744,12 @@ unsafe extern "C" fn call_js_cb<T: 'static, V: ToNapiValue, R, ES>(
|
||||||
err
|
err
|
||||||
);
|
);
|
||||||
let message_length = message.len();
|
let message_length = message.len();
|
||||||
|
let c_message = CString::new(message).unwrap();
|
||||||
unsafe {
|
unsafe {
|
||||||
sys::napi_fatal_error(
|
sys::napi_fatal_error(
|
||||||
"threadsafe_function.rs:720\0".as_ptr().cast(),
|
"threadsafe_function.rs:749\0".as_ptr().cast(),
|
||||||
26,
|
26,
|
||||||
CString::new(message).unwrap().into_raw(),
|
c_message.as_ptr(),
|
||||||
message_length,
|
message_length,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
|
@ -50,6 +50,7 @@ struct JsClassForEither {}
|
||||||
#[napi]
|
#[napi]
|
||||||
impl JsClassForEither {
|
impl JsClassForEither {
|
||||||
#[napi(constructor)]
|
#[napi(constructor)]
|
||||||
|
#[allow(clippy::new_without_default)]
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
JsClassForEither {}
|
JsClassForEither {}
|
||||||
}
|
}
|
||||||
|
@ -60,6 +61,7 @@ struct AnotherClassForEither {}
|
||||||
|
|
||||||
#[napi]
|
#[napi]
|
||||||
impl AnotherClassForEither {
|
impl AnotherClassForEither {
|
||||||
|
#[allow(clippy::new_without_default)]
|
||||||
#[napi(constructor)]
|
#[napi(constructor)]
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {}
|
Self {}
|
||||||
|
|
Loading…
Reference in a new issue