feat(napi): relax the value type on ThreadSafeFunction
This commit is contained in:
parent
89cce5752b
commit
c553dcd4e0
4 changed files with 82 additions and 24 deletions
|
@ -1,10 +1,14 @@
|
||||||
use std::any::TypeId;
|
use std::any::TypeId;
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
|
#[cfg(all(feature = "tokio_rt", feature = "napi4"))]
|
||||||
|
use std::future::Future;
|
||||||
use std::mem;
|
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;
|
||||||
|
|
||||||
|
#[cfg(all(feature = "tokio_rt", feature = "napi4"))]
|
||||||
|
use crate::bindgen_runtime::ToNapiValue;
|
||||||
use crate::{
|
use crate::{
|
||||||
async_work::{self, AsyncWorkPromise},
|
async_work::{self, AsyncWorkPromise},
|
||||||
check_status,
|
check_status,
|
||||||
|
@ -28,8 +32,6 @@ use crate::JsError;
|
||||||
use serde::de::DeserializeOwned;
|
use serde::de::DeserializeOwned;
|
||||||
#[cfg(all(feature = "serde-json"))]
|
#[cfg(all(feature = "serde-json"))]
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
#[cfg(all(feature = "tokio_rt", feature = "napi4"))]
|
|
||||||
use std::future::Future;
|
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
|
@ -1038,7 +1040,7 @@ impl Env {
|
||||||
#[cfg(feature = "napi4")]
|
#[cfg(feature = "napi4")]
|
||||||
pub fn create_threadsafe_function<
|
pub fn create_threadsafe_function<
|
||||||
T: Send,
|
T: Send,
|
||||||
V: NapiRaw,
|
V: ToNapiValue,
|
||||||
R: 'static + Send + FnMut(ThreadSafeCallContext<T>) -> Result<Vec<V>>,
|
R: 'static + Send + FnMut(ThreadSafeCallContext<T>) -> Result<Vec<V>>,
|
||||||
>(
|
>(
|
||||||
&self,
|
&self,
|
||||||
|
@ -1052,7 +1054,7 @@ impl Env {
|
||||||
#[cfg(all(feature = "tokio_rt", feature = "napi4"))]
|
#[cfg(all(feature = "tokio_rt", feature = "napi4"))]
|
||||||
pub fn execute_tokio_future<
|
pub fn execute_tokio_future<
|
||||||
T: 'static + Send,
|
T: 'static + Send,
|
||||||
V: 'static + NapiValue,
|
V: 'static + ToNapiValue,
|
||||||
F: 'static + Send + Future<Output = Result<T>>,
|
F: 'static + Send + Future<Output = Result<T>>,
|
||||||
R: 'static + Send + Sync + FnOnce(&mut Env, T) -> Result<V>,
|
R: 'static + Send + Sync + FnOnce(&mut Env, T) -> Result<V>,
|
||||||
>(
|
>(
|
||||||
|
@ -1063,7 +1065,7 @@ impl Env {
|
||||||
use crate::tokio_runtime;
|
use crate::tokio_runtime;
|
||||||
|
|
||||||
let promise = tokio_runtime::execute_tokio_future(self.0, fut, |env, val| unsafe {
|
let promise = tokio_runtime::execute_tokio_future(self.0, fut, |env, val| unsafe {
|
||||||
resolver(&mut Env::from_raw(env), val).map(|v| v.raw())
|
resolver(&mut Env::from_raw(env), val).and_then(|v| ToNapiValue::to_napi_value(env, v))
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
Ok(unsafe { JsObject::from_raw_unchecked(self.0, promise) })
|
Ok(unsafe { JsObject::from_raw_unchecked(self.0, promise) })
|
||||||
|
|
|
@ -3,7 +3,10 @@ use std::ptr;
|
||||||
use super::Value;
|
use super::Value;
|
||||||
use crate::bindgen_runtime::TypeName;
|
use crate::bindgen_runtime::TypeName;
|
||||||
#[cfg(feature = "napi4")]
|
#[cfg(feature = "napi4")]
|
||||||
use crate::threadsafe_function::{ThreadSafeCallContext, ThreadsafeFunction};
|
use crate::{
|
||||||
|
bindgen_runtime::ToNapiValue,
|
||||||
|
threadsafe_function::{ThreadSafeCallContext, ThreadsafeFunction},
|
||||||
|
};
|
||||||
use crate::{check_status, ValueType};
|
use crate::{check_status, ValueType};
|
||||||
use crate::{sys, Env, Error, JsObject, JsUnknown, NapiRaw, NapiValue, Result, Status};
|
use crate::{sys, Env, Error, JsObject, JsUnknown, NapiRaw, NapiValue, Result, Status};
|
||||||
|
|
||||||
|
@ -127,7 +130,7 @@ impl JsFunction {
|
||||||
) -> Result<ThreadsafeFunction<T, ES>>
|
) -> Result<ThreadsafeFunction<T, ES>>
|
||||||
where
|
where
|
||||||
T: 'static,
|
T: 'static,
|
||||||
V: NapiRaw,
|
V: ToNapiValue,
|
||||||
F: 'static + Send + FnMut(ThreadSafeCallContext<T>) -> Result<Vec<V>>,
|
F: 'static + Send + FnMut(ThreadSafeCallContext<T>) -> Result<Vec<V>>,
|
||||||
ES: crate::threadsafe_function::ErrorStrategy::T,
|
ES: crate::threadsafe_function::ErrorStrategy::T,
|
||||||
{
|
{
|
||||||
|
|
|
@ -8,7 +8,8 @@ use std::ptr;
|
||||||
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
|
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::{check_status, sys, Env, Error, JsError, NapiRaw, Result, Status};
|
use crate::bindgen_runtime::ToNapiValue;
|
||||||
|
use crate::{check_status, sys, Env, Error, JsError, Result, Status};
|
||||||
|
|
||||||
/// ThreadSafeFunction Context object
|
/// ThreadSafeFunction Context object
|
||||||
/// the `value` is the value passed to `call` method
|
/// the `value` is the value passed to `call` method
|
||||||
|
@ -176,7 +177,7 @@ impl<T: 'static, ES: ErrorStrategy::T> ThreadsafeFunction<T, ES> {
|
||||||
/// See [napi_create_threadsafe_function](https://nodejs.org/api/n-api.html#n_api_napi_create_threadsafe_function)
|
/// See [napi_create_threadsafe_function](https://nodejs.org/api/n-api.html#n_api_napi_create_threadsafe_function)
|
||||||
/// for more information.
|
/// for more information.
|
||||||
pub(crate) fn create<
|
pub(crate) fn create<
|
||||||
V: NapiRaw,
|
V: ToNapiValue,
|
||||||
R: 'static + Send + FnMut(ThreadSafeCallContext<T>) -> Result<Vec<V>>,
|
R: 'static + Send + FnMut(ThreadSafeCallContext<T>) -> Result<Vec<V>>,
|
||||||
>(
|
>(
|
||||||
env: sys::napi_env,
|
env: sys::napi_env,
|
||||||
|
@ -330,7 +331,7 @@ unsafe extern "C" fn cleanup_cb(cleanup_data: *mut c_void) {
|
||||||
aborted.store(true, Ordering::SeqCst);
|
aborted.store(true, Ordering::SeqCst);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe extern "C" fn thread_finalize_cb<T: 'static, V: NapiRaw, R>(
|
unsafe extern "C" fn thread_finalize_cb<T: 'static, V: ToNapiValue, R>(
|
||||||
_raw_env: sys::napi_env,
|
_raw_env: sys::napi_env,
|
||||||
finalize_data: *mut c_void,
|
finalize_data: *mut c_void,
|
||||||
_finalize_hint: *mut c_void,
|
_finalize_hint: *mut c_void,
|
||||||
|
@ -341,7 +342,7 @@ unsafe extern "C" fn thread_finalize_cb<T: 'static, V: NapiRaw, R>(
|
||||||
drop(unsafe { Box::<R>::from_raw(finalize_data.cast()) });
|
drop(unsafe { Box::<R>::from_raw(finalize_data.cast()) });
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe extern "C" fn call_js_cb<T: 'static, V: NapiRaw, R, ES>(
|
unsafe extern "C" fn call_js_cb<T: 'static, V: ToNapiValue, R, ES>(
|
||||||
raw_env: sys::napi_env,
|
raw_env: sys::napi_env,
|
||||||
js_callback: sys::napi_value,
|
js_callback: sys::napi_value,
|
||||||
context: *mut c_void,
|
context: *mut c_void,
|
||||||
|
@ -378,15 +379,18 @@ unsafe extern "C" fn call_js_cb<T: 'static, V: NapiRaw, R, ES>(
|
||||||
// If the Result is an error, pass that as the first argument.
|
// If the Result is an error, pass that as the first argument.
|
||||||
let status = match ret {
|
let status = match ret {
|
||||||
Ok(values) => {
|
Ok(values) => {
|
||||||
let values = values.iter().map(|v| unsafe { v.raw() });
|
let values = values
|
||||||
let args: Vec<sys::napi_value> = if ES::VALUE == ErrorStrategy::CalleeHandled::VALUE {
|
.into_iter()
|
||||||
|
.map(|v| unsafe { ToNapiValue::to_napi_value(raw_env, v) });
|
||||||
|
let args: Result<Vec<sys::napi_value>> = if ES::VALUE == ErrorStrategy::CalleeHandled::VALUE {
|
||||||
let mut js_null = ptr::null_mut();
|
let mut js_null = ptr::null_mut();
|
||||||
unsafe { sys::napi_get_null(raw_env, &mut js_null) };
|
unsafe { sys::napi_get_null(raw_env, &mut js_null) };
|
||||||
::core::iter::once(js_null).chain(values).collect()
|
::core::iter::once(Ok(js_null)).chain(values).collect()
|
||||||
} else {
|
} else {
|
||||||
values.collect()
|
values.collect()
|
||||||
};
|
};
|
||||||
unsafe {
|
match args {
|
||||||
|
Ok(args) => unsafe {
|
||||||
sys::napi_call_function(
|
sys::napi_call_function(
|
||||||
raw_env,
|
raw_env,
|
||||||
recv,
|
recv,
|
||||||
|
@ -395,6 +399,22 @@ unsafe extern "C" fn call_js_cb<T: 'static, V: NapiRaw, R, ES>(
|
||||||
args.as_ptr(),
|
args.as_ptr(),
|
||||||
ptr::null_mut(),
|
ptr::null_mut(),
|
||||||
)
|
)
|
||||||
|
},
|
||||||
|
Err(e) => match ES::VALUE {
|
||||||
|
ErrorStrategy::Fatal::VALUE => unsafe {
|
||||||
|
sys::napi_fatal_exception(raw_env, JsError::from(e).into_value(raw_env))
|
||||||
|
},
|
||||||
|
ErrorStrategy::CalleeHandled::VALUE => unsafe {
|
||||||
|
sys::napi_call_function(
|
||||||
|
raw_env,
|
||||||
|
recv,
|
||||||
|
js_callback,
|
||||||
|
1,
|
||||||
|
[JsError::from(e).into_value(raw_env)].as_mut_ptr(),
|
||||||
|
ptr::null_mut(),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) if ES::VALUE == ErrorStrategy::Fatal::VALUE => unsafe {
|
Err(e) if ES::VALUE == ErrorStrategy::Fatal::VALUE => unsafe {
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
use std::env;
|
use std::env;
|
||||||
|
|
||||||
use napi::bindgen_prelude::*;
|
use napi::{
|
||||||
|
bindgen_prelude::*,
|
||||||
|
threadsafe_function::{ThreadSafeCallContext, ThreadsafeFunction, ThreadsafeFunctionCallMode},
|
||||||
|
JsUnknown,
|
||||||
|
};
|
||||||
|
|
||||||
#[napi]
|
#[napi]
|
||||||
fn get_cwd<T: Fn(String) -> Result<()>>(callback: T) {
|
fn get_cwd<T: Fn(String) -> Result<()>>(callback: T) {
|
||||||
|
@ -46,3 +50,32 @@ fn read_file_content() -> Result<String> {
|
||||||
fn return_js_function(env: Env) -> Result<JsFunction> {
|
fn return_js_function(env: Env) -> Result<JsFunction> {
|
||||||
get_js_function(&env, read_file_js_function)
|
get_js_function(&env, read_file_js_function)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[napi(
|
||||||
|
ts_generic_types = "T",
|
||||||
|
ts_args_type = "functionInput: () => T | Promise<T>, callback: (err: Error | null, result: T) => void"
|
||||||
|
)]
|
||||||
|
fn callback_return_promise<T: Fn() -> Result<JsUnknown>>(
|
||||||
|
env: Env,
|
||||||
|
fn_in: T,
|
||||||
|
fn_out: JsFunction,
|
||||||
|
) -> Result<JsUnknown> {
|
||||||
|
let ret = fn_in()?;
|
||||||
|
if ret.is_promise()? {
|
||||||
|
let p = Promise::<String>::from_unknown(ret)?;
|
||||||
|
let fn_out_tsfn: ThreadsafeFunction<String> = fn_out
|
||||||
|
.create_threadsafe_function(0, |ctx: ThreadSafeCallContext<String>| Ok(vec![ctx.value]))?;
|
||||||
|
env
|
||||||
|
.execute_tokio_future(
|
||||||
|
async move {
|
||||||
|
let s = p.await;
|
||||||
|
fn_out_tsfn.call(s, ThreadsafeFunctionCallMode::NonBlocking);
|
||||||
|
Ok::<(), Error>(())
|
||||||
|
},
|
||||||
|
|env, _| env.get_undefined(),
|
||||||
|
)
|
||||||
|
.map(|v| v.into_unknown())
|
||||||
|
} else {
|
||||||
|
Ok(ret)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue