feat(napi): convert ToNapiValue tuple to variadic tsfn (#1475)
* refactor: convert ToNapiValue tuple to variadic tsfn * chore: resolve conflicts * fix: typo * chore: use into instead of to * chore: syntax compat
This commit is contained in:
parent
a7dcf2a838
commit
90cc0a6abe
10 changed files with 202 additions and 53 deletions
|
@ -218,6 +218,12 @@ fn is_ts_union_type(rust_ty: &str) -> bool {
|
|||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
const TSFN_RUST_TY: &str = "ThreadsafeFunction";
|
||||
|
||||
fn should_convert_tuple_to_variadic(rust_ty: &str) -> bool {
|
||||
rust_ty == TSFN_RUST_TY
|
||||
}
|
||||
|
||||
fn is_ts_function_type_notation(ty: &Type) -> bool {
|
||||
match ty {
|
||||
Type::Path(syn::TypePath { qself: None, path }) => {
|
||||
|
@ -235,12 +241,32 @@ fn is_ts_function_type_notation(ty: &Type) -> bool {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn ty_to_ts_type(ty: &Type, is_return_ty: bool, is_struct_field: bool) -> (String, bool) {
|
||||
pub fn ty_to_ts_type(
|
||||
ty: &Type,
|
||||
is_return_ty: bool,
|
||||
is_struct_field: bool,
|
||||
convert_tuple_to_variadic: bool,
|
||||
) -> (String, bool, bool) {
|
||||
match ty {
|
||||
Type::Reference(r) => ty_to_ts_type(&r.elem, is_return_ty, is_struct_field),
|
||||
Type::Reference(r) => ty_to_ts_type(&r.elem, is_return_ty, is_struct_field, false),
|
||||
Type::Tuple(tuple) => {
|
||||
if tuple.elems.is_empty() {
|
||||
("undefined".to_owned(), false)
|
||||
("undefined".to_owned(), false, false)
|
||||
} else if convert_tuple_to_variadic {
|
||||
let variadic = &tuple
|
||||
.elems
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, arg)| {
|
||||
let (ts_type, is_optional, _) = ty_to_ts_type(arg, false, false, false);
|
||||
r#fn::FnArg {
|
||||
arg: format!("arg{}", i),
|
||||
ts_type,
|
||||
is_optional,
|
||||
}
|
||||
})
|
||||
.collect::<r#fn::FnArgList>();
|
||||
(format!("{}", variadic), false, true)
|
||||
} else {
|
||||
(
|
||||
format!(
|
||||
|
@ -248,11 +274,12 @@ pub fn ty_to_ts_type(ty: &Type, is_return_ty: bool, is_struct_field: bool) -> (S
|
|||
tuple
|
||||
.elems
|
||||
.iter()
|
||||
.map(|elem| ty_to_ts_type(elem, false, false).0)
|
||||
.map(|elem| ty_to_ts_type(elem, false, false, false).0)
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
),
|
||||
false,
|
||||
false,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -267,14 +294,18 @@ pub fn ty_to_ts_type(ty: &Type, is_return_ty: bool, is_struct_field: bool) -> (S
|
|||
.args
|
||||
.iter()
|
||||
.filter_map(|arg| match arg {
|
||||
syn::GenericArgument::Type(generic_ty) => {
|
||||
Some(ty_to_ts_type(generic_ty, false, false)).map(|(mut ty, is_struct_field)| {
|
||||
if is_ts_union_type && is_ts_function_type_notation(generic_ty) {
|
||||
ty = format!("({})", ty);
|
||||
}
|
||||
(ty, is_struct_field)
|
||||
})
|
||||
}
|
||||
syn::GenericArgument::Type(generic_ty) => Some(ty_to_ts_type(
|
||||
generic_ty,
|
||||
false,
|
||||
false,
|
||||
should_convert_tuple_to_variadic(&rust_ty),
|
||||
))
|
||||
.map(|(mut ty, is_optional, is_variadic)| {
|
||||
if is_ts_union_type && is_ts_function_type_notation(generic_ty) {
|
||||
ty = format!("({})", ty);
|
||||
}
|
||||
(ty, is_optional, is_variadic)
|
||||
}),
|
||||
_ => None,
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
|
@ -285,7 +316,7 @@ pub fn ty_to_ts_type(ty: &Type, is_return_ty: bool, is_struct_field: bool) -> (S
|
|||
if rust_ty == "Result" && is_return_ty {
|
||||
ts_ty = Some(args.first().unwrap().to_owned());
|
||||
} else if rust_ty == "Option" {
|
||||
ts_ty = args.first().map(|(arg, _)| {
|
||||
ts_ty = args.first().map(|(arg, _, _)| {
|
||||
(
|
||||
if is_struct_field {
|
||||
arg.to_string()
|
||||
|
@ -295,56 +326,78 @@ pub fn ty_to_ts_type(ty: &Type, is_return_ty: bool, is_struct_field: bool) -> (S
|
|||
format!("{} | undefined | null", arg)
|
||||
},
|
||||
true,
|
||||
false,
|
||||
)
|
||||
});
|
||||
} else if rust_ty == "AsyncTask" {
|
||||
ts_ty = r#struct::TASK_STRUCTS.with(|t| {
|
||||
let (output_type, _) = args.first().unwrap().to_owned();
|
||||
let (output_type, _, _) = args.first().unwrap().to_owned();
|
||||
if let Some(o) = t.borrow().get(&output_type) {
|
||||
Some((format!("Promise<{}>", o), false))
|
||||
Some((format!("Promise<{}>", o), false, false))
|
||||
} else {
|
||||
Some(("Promise<unknown>".to_owned(), false))
|
||||
Some(("Promise<unknown>".to_owned(), false, false))
|
||||
}
|
||||
});
|
||||
} else if rust_ty == "Reference" || rust_ty == "WeakReference" {
|
||||
ts_ty = r#struct::TASK_STRUCTS.with(|t| {
|
||||
// Reference<T> => T
|
||||
if let Some(arg) = args.first() {
|
||||
let (output_type, _) = arg.to_owned();
|
||||
let (output_type, _, _) = arg.to_owned();
|
||||
if let Some(o) = t.borrow().get(&output_type) {
|
||||
Some((o.to_owned(), false))
|
||||
Some((o.to_owned(), false, false))
|
||||
} else {
|
||||
Some((output_type, false))
|
||||
Some((output_type, false, false))
|
||||
}
|
||||
} else {
|
||||
// Not NAPI-RS `Reference`
|
||||
Some((rust_ty, false))
|
||||
Some((rust_ty, false, false))
|
||||
}
|
||||
});
|
||||
} else if let Some(&(known_ty, _, _)) = KNOWN_TYPES.get(rust_ty.as_str()) {
|
||||
if known_ty.contains("{}") {
|
||||
ts_ty = Some((
|
||||
fill_ty(known_ty, args.into_iter().map(|(arg, _)| arg).collect()),
|
||||
fill_ty(known_ty, args.into_iter().map(|(arg, _, _)| arg).collect()),
|
||||
false,
|
||||
false,
|
||||
));
|
||||
} else {
|
||||
ts_ty = Some((known_ty.to_owned(), false));
|
||||
ts_ty = Some((known_ty.to_owned(), false, false));
|
||||
}
|
||||
} else if let Some(t) = crate::typegen::r#struct::CLASS_STRUCTS
|
||||
.with(|c| c.borrow_mut().get(rust_ty.as_str()).cloned())
|
||||
{
|
||||
ts_ty = Some((t, false));
|
||||
} else if rust_ty == "ThreadsafeFunction" {
|
||||
ts_ty = Some((t, false, false));
|
||||
} else if rust_ty == TSFN_RUST_TY {
|
||||
let fatal_tsfn = match args.get(1) {
|
||||
Some((arg, _)) => arg == "Fatal",
|
||||
Some((arg, _, _)) => arg == "Fatal",
|
||||
_ => false,
|
||||
};
|
||||
let first_arg = args.first().map(|(arg, _)| arg).unwrap();
|
||||
let (args, is_variadic) = args
|
||||
.first()
|
||||
.map(|(arg, _, is_variadic)| (arg, is_variadic))
|
||||
.unwrap();
|
||||
ts_ty = if fatal_tsfn {
|
||||
Some((format!("(value: {}) => any", first_arg), false))
|
||||
Some((
|
||||
{
|
||||
if *is_variadic {
|
||||
format!("({}) => any", args)
|
||||
} else {
|
||||
format!("(value: {}) => any", args)
|
||||
}
|
||||
},
|
||||
false,
|
||||
false,
|
||||
))
|
||||
} else {
|
||||
Some((
|
||||
format!("(err: Error | null, value: {}) => any", first_arg),
|
||||
{
|
||||
if *is_variadic {
|
||||
format!("(err: Error | null, {}) => any", args)
|
||||
} else {
|
||||
format!("(err: Error | null, value: {}) => any", args)
|
||||
}
|
||||
},
|
||||
false,
|
||||
false,
|
||||
))
|
||||
};
|
||||
|
@ -354,19 +407,25 @@ pub fn ty_to_ts_type(ty: &Type, is_return_ty: bool, is_struct_field: bool) -> (S
|
|||
aliases
|
||||
.borrow()
|
||||
.get(rust_ty.as_str())
|
||||
.map(|a| (a.to_owned(), false))
|
||||
.map(|a| (a.to_owned(), false, false))
|
||||
});
|
||||
ts_ty = type_alias.or(Some((rust_ty, false)));
|
||||
ts_ty = type_alias.or(Some((rust_ty, false, false)));
|
||||
}
|
||||
}
|
||||
|
||||
ts_ty.unwrap_or_else(|| ("any".to_owned(), false))
|
||||
ts_ty.unwrap_or_else(|| ("any".to_owned(), false, false))
|
||||
}
|
||||
Type::Group(g) => ty_to_ts_type(&g.elem, is_return_ty, is_struct_field),
|
||||
Type::Group(g) => ty_to_ts_type(&g.elem, is_return_ty, is_struct_field, false),
|
||||
Type::Array(a) => {
|
||||
let (element_type, is_optional) = ty_to_ts_type(&a.elem, is_return_ty, is_struct_field);
|
||||
(format!("{}[]", element_type), is_optional)
|
||||
let (element_type, is_optional, _) =
|
||||
ty_to_ts_type(&a.elem, is_return_ty, is_struct_field, false);
|
||||
(format!("{}[]", element_type), is_optional, false)
|
||||
}
|
||||
_ => ("any".to_owned(), false),
|
||||
Type::Paren(p) => {
|
||||
let (element_type, is_optional, _) =
|
||||
ty_to_ts_type(&p.elem, is_return_ty, is_struct_field, false);
|
||||
(element_type, is_optional, false)
|
||||
}
|
||||
_ => ("any".to_owned(), false, false),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ impl ToTypeDef for NapiConst {
|
|||
def: format!(
|
||||
"export const {}: {}",
|
||||
&self.js_name,
|
||||
ty_to_ts_type(&self.type_name, false, false).0
|
||||
ty_to_ts_type(&self.type_name, false, false, false).0
|
||||
),
|
||||
js_mod: self.js_mod.to_owned(),
|
||||
js_doc: js_doc_from_comments(&self.comments),
|
||||
|
|
|
@ -6,13 +6,13 @@ use syn::{Pat, PathArguments, PathSegment};
|
|||
use super::{ty_to_ts_type, ToTypeDef, TypeDef};
|
||||
use crate::{js_doc_from_comments, CallbackArg, FnKind, NapiFn};
|
||||
|
||||
struct FnArg {
|
||||
arg: String,
|
||||
ts_type: String,
|
||||
is_optional: bool,
|
||||
pub(crate) struct FnArg {
|
||||
pub(crate) arg: String,
|
||||
pub(crate) ts_type: String,
|
||||
pub(crate) is_optional: bool,
|
||||
}
|
||||
|
||||
struct FnArgList {
|
||||
pub(crate) struct FnArgList {
|
||||
this: Option<FnArg>,
|
||||
args: Vec<FnArg>,
|
||||
last_required: Option<usize>,
|
||||
|
@ -110,7 +110,7 @@ fn gen_callback_type(callback: &CallbackArg) -> String {
|
|||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, arg)| {
|
||||
let (ts_type, is_optional) = ty_to_ts_type(arg, false, false);
|
||||
let (ts_type, is_optional, _) = ty_to_ts_type(arg, false, false, false);
|
||||
FnArg {
|
||||
arg: format!("arg{}", i),
|
||||
ts_type,
|
||||
|
@ -119,7 +119,7 @@ fn gen_callback_type(callback: &CallbackArg) -> String {
|
|||
})
|
||||
.collect::<FnArgList>(),
|
||||
ret = match &callback.ret {
|
||||
Some(ty) => ty_to_ts_type(ty, true, false).0,
|
||||
Some(ty) => ty_to_ts_type(ty, true, false, false).0,
|
||||
None => "void".to_owned(),
|
||||
}
|
||||
)
|
||||
|
@ -153,7 +153,7 @@ impl NapiFn {
|
|||
}) = arguments
|
||||
{
|
||||
if let Some(syn::GenericArgument::Type(ty)) = angle_bracketed_args.first() {
|
||||
let (ts_type, _) = ty_to_ts_type(ty, false, false);
|
||||
let (ts_type, _, _) = ty_to_ts_type(ty, false, false, false);
|
||||
return Some(FnArg {
|
||||
arg: "this".to_owned(),
|
||||
ts_type,
|
||||
|
@ -178,7 +178,7 @@ impl NapiFn {
|
|||
i.mutability = None;
|
||||
}
|
||||
|
||||
let (ts_type, is_optional) = ty_to_ts_type(&path.ty, false, false);
|
||||
let (ts_type, is_optional, _) = ty_to_ts_type(&path.ty, false, false, false);
|
||||
let ts_type = arg.use_overridden_type_or(|| ts_type);
|
||||
let arg = path.pat.to_token_stream().to_string().to_case(Case::Camel);
|
||||
|
||||
|
@ -230,7 +230,7 @@ impl NapiFn {
|
|||
.unwrap_or_else(|| "".to_owned()),
|
||||
_ => {
|
||||
let ret = if let Some(ret) = &self.ret {
|
||||
let (ts_type, _) = ty_to_ts_type(ret, true, false);
|
||||
let (ts_type, _, _) = ty_to_ts_type(ret, true, false, false);
|
||||
if ts_type == "undefined" {
|
||||
"void".to_owned()
|
||||
} else if ts_type == "Self" {
|
||||
|
|
|
@ -38,19 +38,19 @@ impl ToTypeDef for NapiImpl {
|
|||
TASK_STRUCTS.with(|t| {
|
||||
t.borrow_mut().insert(
|
||||
self.name.to_string(),
|
||||
ty_to_ts_type(output_type, false, true).0,
|
||||
ty_to_ts_type(output_type, false, true, false).0,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
if let Some(output_type) = &self.iterator_yield_type {
|
||||
let next_type = if let Some(ref ty) = self.iterator_next_type {
|
||||
ty_to_ts_type(ty, false, false).0
|
||||
ty_to_ts_type(ty, false, false, false).0
|
||||
} else {
|
||||
"void".to_owned()
|
||||
};
|
||||
let return_type = if let Some(ref ty) = self.iterator_return_type {
|
||||
ty_to_ts_type(ty, false, false).0
|
||||
ty_to_ts_type(ty, false, false, false).0
|
||||
} else {
|
||||
"void".to_owned()
|
||||
};
|
||||
|
@ -60,7 +60,7 @@ impl ToTypeDef for NapiImpl {
|
|||
original_name: None,
|
||||
def: format!(
|
||||
"[Symbol.iterator](): Iterator<{}, {}, {}>",
|
||||
ty_to_ts_type(output_type, false, true).0,
|
||||
ty_to_ts_type(output_type, false, true, false).0,
|
||||
return_type,
|
||||
next_type,
|
||||
),
|
||||
|
@ -118,7 +118,7 @@ impl NapiStruct {
|
|||
field_str.push_str("readonly ")
|
||||
}
|
||||
|
||||
let (arg, is_optional) = ty_to_ts_type(&f.ty, false, true);
|
||||
let (arg, is_optional, _) = ty_to_ts_type(&f.ty, false, true, false);
|
||||
let arg = f.ts_type.as_ref().map(|ty| ty.to_string()).unwrap_or(arg);
|
||||
|
||||
let sep = if is_optional { "?" } else { "" };
|
||||
|
|
|
@ -208,9 +208,72 @@ impl<T: 'static, ES: ErrorStrategy::T> Clone for ThreadsafeFunction<T, ES> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: ToNapiValue + 'static, ES: ErrorStrategy::T> FromNapiValue for ThreadsafeFunction<T, ES> {
|
||||
pub trait JsValuesTupleIntoVec {
|
||||
fn into_vec(self, env: &Env) -> Result<Vec<JsUnknown>>;
|
||||
}
|
||||
|
||||
impl<T: ToNapiValue> JsValuesTupleIntoVec for T {
|
||||
fn into_vec(self, env: &Env) -> Result<Vec<JsUnknown>> {
|
||||
Ok(vec![JsUnknown(crate::Value {
|
||||
env: env.0,
|
||||
value: unsafe { <T as ToNapiValue>::to_napi_value(env.0, self)? },
|
||||
value_type: crate::ValueType::Unknown,
|
||||
})])
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_js_value_tuple_to_vec {
|
||||
($($ident:ident),*) => {
|
||||
impl<$($ident: ToNapiValue),*> JsValuesTupleIntoVec for ($($ident,)*) {
|
||||
fn into_vec(self, env: &Env) -> Result<Vec<JsUnknown>> {
|
||||
#[allow(non_snake_case)]
|
||||
let ($($ident,)*) = self;
|
||||
Ok(vec![$(JsUnknown($crate::Value {
|
||||
env: env.0,
|
||||
value: unsafe { <$ident as ToNapiValue>::to_napi_value(env.0, $ident)? },
|
||||
value_type: $crate::ValueType::Unknown,
|
||||
})),*])
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_js_value_tuple_to_vec!(A);
|
||||
impl_js_value_tuple_to_vec!(A, B);
|
||||
impl_js_value_tuple_to_vec!(A, B, C);
|
||||
impl_js_value_tuple_to_vec!(A, B, C, D);
|
||||
impl_js_value_tuple_to_vec!(A, B, C, D, E);
|
||||
impl_js_value_tuple_to_vec!(A, B, C, D, E, F);
|
||||
impl_js_value_tuple_to_vec!(A, B, C, D, E, F, G);
|
||||
impl_js_value_tuple_to_vec!(A, B, C, D, E, F, G, H);
|
||||
impl_js_value_tuple_to_vec!(A, B, C, D, E, F, G, H, I);
|
||||
impl_js_value_tuple_to_vec!(A, B, C, D, E, F, G, H, I, J);
|
||||
impl_js_value_tuple_to_vec!(A, B, C, D, E, F, G, H, I, J, K);
|
||||
impl_js_value_tuple_to_vec!(A, B, C, D, E, F, G, H, I, J, K, L);
|
||||
impl_js_value_tuple_to_vec!(A, B, C, D, E, F, G, H, I, J, K, L, M);
|
||||
impl_js_value_tuple_to_vec!(A, B, C, D, E, F, G, H, I, J, K, L, M, N);
|
||||
impl_js_value_tuple_to_vec!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O);
|
||||
impl_js_value_tuple_to_vec!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);
|
||||
impl_js_value_tuple_to_vec!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q);
|
||||
impl_js_value_tuple_to_vec!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R);
|
||||
impl_js_value_tuple_to_vec!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S);
|
||||
impl_js_value_tuple_to_vec!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T);
|
||||
impl_js_value_tuple_to_vec!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U);
|
||||
impl_js_value_tuple_to_vec!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V);
|
||||
impl_js_value_tuple_to_vec!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W);
|
||||
impl_js_value_tuple_to_vec!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X);
|
||||
impl_js_value_tuple_to_vec!(
|
||||
A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y
|
||||
);
|
||||
impl_js_value_tuple_to_vec!(
|
||||
A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z
|
||||
);
|
||||
|
||||
impl<T: JsValuesTupleIntoVec + 'static, ES: ErrorStrategy::T> FromNapiValue
|
||||
for ThreadsafeFunction<T, ES>
|
||||
{
|
||||
unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
|
||||
Self::create(env, napi_val, 0, |ctx| Ok(vec![ctx.value]))
|
||||
Self::create(env, napi_val, 0, |ctx| ctx.value.into_vec(&ctx.env))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -209,6 +209,7 @@ Generated by [AVA](https://avajs.dev).
|
|||
export function tsfnAsyncCall(func: (...args: any[]) => any): Promise<void>␊
|
||||
export function acceptThreadsafeFunction(func: (err: Error | null, value: number) => any): void␊
|
||||
export function acceptThreadsafeFunctionFatal(func: (value: number) => any): void␊
|
||||
export function acceptThreadsafeFunctionTupleArgs(func: (err: Error | null, arg0: number, arg1: boolean, arg2: string) => any): void␊
|
||||
export function getBuffer(): Buffer␊
|
||||
export function appendBuffer(buf: Buffer): Buffer␊
|
||||
export function getEmptyBuffer(): Buffer␊
|
||||
|
|
Binary file not shown.
|
@ -119,6 +119,7 @@ import {
|
|||
bigintFromI64,
|
||||
acceptThreadsafeFunction,
|
||||
acceptThreadsafeFunctionFatal,
|
||||
acceptThreadsafeFunctionTupleArgs,
|
||||
promiseInEither,
|
||||
runScript,
|
||||
} from '../'
|
||||
|
@ -827,6 +828,20 @@ Napi4Test('accept ThreadsafeFunction Fatal', async (t) => {
|
|||
})
|
||||
})
|
||||
|
||||
Napi4Test('accept ThreadsafeFunction tuple args', async (t) => {
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
acceptThreadsafeFunctionTupleArgs((err, num, bool, str) => {
|
||||
if (err) {
|
||||
return reject(err)
|
||||
}
|
||||
t.is(num, 1)
|
||||
t.is(bool, false)
|
||||
t.is(str, 'NAPI-RS')
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Napi4Test('object only from js', (t) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
receiveObjectOnlyFromJs({
|
||||
|
|
1
examples/napi/index.d.ts
vendored
1
examples/napi/index.d.ts
vendored
|
@ -199,6 +199,7 @@ export function tsfnCallWithCallback(func: (...args: any[]) => any): void
|
|||
export function tsfnAsyncCall(func: (...args: any[]) => any): Promise<void>
|
||||
export function acceptThreadsafeFunction(func: (err: Error | null, value: number) => any): void
|
||||
export function acceptThreadsafeFunctionFatal(func: (value: number) => any): void
|
||||
export function acceptThreadsafeFunctionTupleArgs(func: (err: Error | null, arg0: number, arg1: boolean, arg2: string) => any): void
|
||||
export function getBuffer(): Buffer
|
||||
export function appendBuffer(buf: Buffer): Buffer
|
||||
export function getEmptyBuffer(): Buffer
|
||||
|
|
|
@ -116,3 +116,13 @@ pub fn accept_threadsafe_function_fatal(func: ThreadsafeFunction<u32, ErrorStrat
|
|||
func.call(1, ThreadsafeFunctionCallMode::NonBlocking);
|
||||
});
|
||||
}
|
||||
|
||||
#[napi]
|
||||
pub fn accept_threadsafe_function_tuple_args(func: ThreadsafeFunction<(u32, bool, String)>) {
|
||||
thread::spawn(move || {
|
||||
func.call(
|
||||
Ok((1, false, "NAPI-RS".into())),
|
||||
ThreadsafeFunctionCallMode::NonBlocking,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue