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)
|
.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 {
|
fn is_ts_function_type_notation(ty: &Type) -> bool {
|
||||||
match ty {
|
match ty {
|
||||||
Type::Path(syn::TypePath { qself: None, path }) => {
|
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 {
|
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) => {
|
Type::Tuple(tuple) => {
|
||||||
if tuple.elems.is_empty() {
|
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 {
|
} else {
|
||||||
(
|
(
|
||||||
format!(
|
format!(
|
||||||
|
@ -248,11 +274,12 @@ pub fn ty_to_ts_type(ty: &Type, is_return_ty: bool, is_struct_field: bool) -> (S
|
||||||
tuple
|
tuple
|
||||||
.elems
|
.elems
|
||||||
.iter()
|
.iter()
|
||||||
.map(|elem| ty_to_ts_type(elem, false, false).0)
|
.map(|elem| ty_to_ts_type(elem, false, false, false).0)
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join(", ")
|
.join(", ")
|
||||||
),
|
),
|
||||||
false,
|
false,
|
||||||
|
false,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -267,14 +294,18 @@ pub fn ty_to_ts_type(ty: &Type, is_return_ty: bool, is_struct_field: bool) -> (S
|
||||||
.args
|
.args
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|arg| match arg {
|
.filter_map(|arg| match arg {
|
||||||
syn::GenericArgument::Type(generic_ty) => {
|
syn::GenericArgument::Type(generic_ty) => Some(ty_to_ts_type(
|
||||||
Some(ty_to_ts_type(generic_ty, false, false)).map(|(mut ty, is_struct_field)| {
|
generic_ty,
|
||||||
if is_ts_union_type && is_ts_function_type_notation(generic_ty) {
|
false,
|
||||||
ty = format!("({})", ty);
|
false,
|
||||||
}
|
should_convert_tuple_to_variadic(&rust_ty),
|
||||||
(ty, is_struct_field)
|
))
|
||||||
})
|
.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,
|
_ => None,
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>()
|
.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 {
|
if rust_ty == "Result" && is_return_ty {
|
||||||
ts_ty = Some(args.first().unwrap().to_owned());
|
ts_ty = Some(args.first().unwrap().to_owned());
|
||||||
} else if rust_ty == "Option" {
|
} else if rust_ty == "Option" {
|
||||||
ts_ty = args.first().map(|(arg, _)| {
|
ts_ty = args.first().map(|(arg, _, _)| {
|
||||||
(
|
(
|
||||||
if is_struct_field {
|
if is_struct_field {
|
||||||
arg.to_string()
|
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)
|
format!("{} | undefined | null", arg)
|
||||||
},
|
},
|
||||||
true,
|
true,
|
||||||
|
false,
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
} else if rust_ty == "AsyncTask" {
|
} else if rust_ty == "AsyncTask" {
|
||||||
ts_ty = r#struct::TASK_STRUCTS.with(|t| {
|
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) {
|
if let Some(o) = t.borrow().get(&output_type) {
|
||||||
Some((format!("Promise<{}>", o), false))
|
Some((format!("Promise<{}>", o), false, false))
|
||||||
} else {
|
} else {
|
||||||
Some(("Promise<unknown>".to_owned(), false))
|
Some(("Promise<unknown>".to_owned(), false, false))
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else if rust_ty == "Reference" || rust_ty == "WeakReference" {
|
} else if rust_ty == "Reference" || rust_ty == "WeakReference" {
|
||||||
ts_ty = r#struct::TASK_STRUCTS.with(|t| {
|
ts_ty = r#struct::TASK_STRUCTS.with(|t| {
|
||||||
// Reference<T> => T
|
// Reference<T> => T
|
||||||
if let Some(arg) = args.first() {
|
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) {
|
if let Some(o) = t.borrow().get(&output_type) {
|
||||||
Some((o.to_owned(), false))
|
Some((o.to_owned(), false, false))
|
||||||
} else {
|
} else {
|
||||||
Some((output_type, false))
|
Some((output_type, false, false))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Not NAPI-RS `Reference`
|
// 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()) {
|
} else if let Some(&(known_ty, _, _)) = KNOWN_TYPES.get(rust_ty.as_str()) {
|
||||||
if known_ty.contains("{}") {
|
if known_ty.contains("{}") {
|
||||||
ts_ty = Some((
|
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,
|
false,
|
||||||
));
|
));
|
||||||
} else {
|
} 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
|
} else if let Some(t) = crate::typegen::r#struct::CLASS_STRUCTS
|
||||||
.with(|c| c.borrow_mut().get(rust_ty.as_str()).cloned())
|
.with(|c| c.borrow_mut().get(rust_ty.as_str()).cloned())
|
||||||
{
|
{
|
||||||
ts_ty = Some((t, false));
|
ts_ty = Some((t, false, false));
|
||||||
} else if rust_ty == "ThreadsafeFunction" {
|
} else if rust_ty == TSFN_RUST_TY {
|
||||||
let fatal_tsfn = match args.get(1) {
|
let fatal_tsfn = match args.get(1) {
|
||||||
Some((arg, _)) => arg == "Fatal",
|
Some((arg, _, _)) => arg == "Fatal",
|
||||||
_ => false,
|
_ => 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 {
|
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 {
|
} else {
|
||||||
Some((
|
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,
|
false,
|
||||||
))
|
))
|
||||||
};
|
};
|
||||||
|
@ -354,19 +407,25 @@ pub fn ty_to_ts_type(ty: &Type, is_return_ty: bool, is_struct_field: bool) -> (S
|
||||||
aliases
|
aliases
|
||||||
.borrow()
|
.borrow()
|
||||||
.get(rust_ty.as_str())
|
.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) => {
|
Type::Array(a) => {
|
||||||
let (element_type, is_optional) = ty_to_ts_type(&a.elem, is_return_ty, is_struct_field);
|
let (element_type, is_optional, _) =
|
||||||
(format!("{}[]", 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!(
|
def: format!(
|
||||||
"export const {}: {}",
|
"export const {}: {}",
|
||||||
&self.js_name,
|
&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_mod: self.js_mod.to_owned(),
|
||||||
js_doc: js_doc_from_comments(&self.comments),
|
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 super::{ty_to_ts_type, ToTypeDef, TypeDef};
|
||||||
use crate::{js_doc_from_comments, CallbackArg, FnKind, NapiFn};
|
use crate::{js_doc_from_comments, CallbackArg, FnKind, NapiFn};
|
||||||
|
|
||||||
struct FnArg {
|
pub(crate) struct FnArg {
|
||||||
arg: String,
|
pub(crate) arg: String,
|
||||||
ts_type: String,
|
pub(crate) ts_type: String,
|
||||||
is_optional: bool,
|
pub(crate) is_optional: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct FnArgList {
|
pub(crate) struct FnArgList {
|
||||||
this: Option<FnArg>,
|
this: Option<FnArg>,
|
||||||
args: Vec<FnArg>,
|
args: Vec<FnArg>,
|
||||||
last_required: Option<usize>,
|
last_required: Option<usize>,
|
||||||
|
@ -110,7 +110,7 @@ fn gen_callback_type(callback: &CallbackArg) -> String {
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(i, arg)| {
|
.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 {
|
FnArg {
|
||||||
arg: format!("arg{}", i),
|
arg: format!("arg{}", i),
|
||||||
ts_type,
|
ts_type,
|
||||||
|
@ -119,7 +119,7 @@ fn gen_callback_type(callback: &CallbackArg) -> String {
|
||||||
})
|
})
|
||||||
.collect::<FnArgList>(),
|
.collect::<FnArgList>(),
|
||||||
ret = match &callback.ret {
|
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(),
|
None => "void".to_owned(),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -153,7 +153,7 @@ impl NapiFn {
|
||||||
}) = arguments
|
}) = arguments
|
||||||
{
|
{
|
||||||
if let Some(syn::GenericArgument::Type(ty)) = angle_bracketed_args.first() {
|
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 {
|
return Some(FnArg {
|
||||||
arg: "this".to_owned(),
|
arg: "this".to_owned(),
|
||||||
ts_type,
|
ts_type,
|
||||||
|
@ -178,7 +178,7 @@ impl NapiFn {
|
||||||
i.mutability = None;
|
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 ts_type = arg.use_overridden_type_or(|| ts_type);
|
||||||
let arg = path.pat.to_token_stream().to_string().to_case(Case::Camel);
|
let arg = path.pat.to_token_stream().to_string().to_case(Case::Camel);
|
||||||
|
|
||||||
|
@ -230,7 +230,7 @@ impl NapiFn {
|
||||||
.unwrap_or_else(|| "".to_owned()),
|
.unwrap_or_else(|| "".to_owned()),
|
||||||
_ => {
|
_ => {
|
||||||
let ret = if let Some(ret) = &self.ret {
|
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" {
|
if ts_type == "undefined" {
|
||||||
"void".to_owned()
|
"void".to_owned()
|
||||||
} else if ts_type == "Self" {
|
} else if ts_type == "Self" {
|
||||||
|
|
|
@ -38,19 +38,19 @@ impl ToTypeDef for NapiImpl {
|
||||||
TASK_STRUCTS.with(|t| {
|
TASK_STRUCTS.with(|t| {
|
||||||
t.borrow_mut().insert(
|
t.borrow_mut().insert(
|
||||||
self.name.to_string(),
|
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 {
|
if let Some(output_type) = &self.iterator_yield_type {
|
||||||
let next_type = if let Some(ref ty) = self.iterator_next_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 {
|
} else {
|
||||||
"void".to_owned()
|
"void".to_owned()
|
||||||
};
|
};
|
||||||
let return_type = if let Some(ref ty) = self.iterator_return_type {
|
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 {
|
} else {
|
||||||
"void".to_owned()
|
"void".to_owned()
|
||||||
};
|
};
|
||||||
|
@ -60,7 +60,7 @@ impl ToTypeDef for NapiImpl {
|
||||||
original_name: None,
|
original_name: None,
|
||||||
def: format!(
|
def: format!(
|
||||||
"[Symbol.iterator](): Iterator<{}, {}, {}>",
|
"[Symbol.iterator](): Iterator<{}, {}, {}>",
|
||||||
ty_to_ts_type(output_type, false, true).0,
|
ty_to_ts_type(output_type, false, true, false).0,
|
||||||
return_type,
|
return_type,
|
||||||
next_type,
|
next_type,
|
||||||
),
|
),
|
||||||
|
@ -118,7 +118,7 @@ impl NapiStruct {
|
||||||
field_str.push_str("readonly ")
|
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 arg = f.ts_type.as_ref().map(|ty| ty.to_string()).unwrap_or(arg);
|
||||||
|
|
||||||
let sep = if is_optional { "?" } else { "" };
|
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> {
|
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 tsfnAsyncCall(func: (...args: any[]) => any): Promise<void>␊
|
||||||
export function acceptThreadsafeFunction(func: (err: Error | null, value: number) => any): void␊
|
export function acceptThreadsafeFunction(func: (err: Error | null, value: number) => any): void␊
|
||||||
export function acceptThreadsafeFunctionFatal(func: (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 getBuffer(): Buffer␊
|
||||||
export function appendBuffer(buf: Buffer): Buffer␊
|
export function appendBuffer(buf: Buffer): Buffer␊
|
||||||
export function getEmptyBuffer(): Buffer␊
|
export function getEmptyBuffer(): Buffer␊
|
||||||
|
|
Binary file not shown.
|
@ -119,6 +119,7 @@ import {
|
||||||
bigintFromI64,
|
bigintFromI64,
|
||||||
acceptThreadsafeFunction,
|
acceptThreadsafeFunction,
|
||||||
acceptThreadsafeFunctionFatal,
|
acceptThreadsafeFunctionFatal,
|
||||||
|
acceptThreadsafeFunctionTupleArgs,
|
||||||
promiseInEither,
|
promiseInEither,
|
||||||
runScript,
|
runScript,
|
||||||
} from '../'
|
} 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) => {
|
Napi4Test('object only from js', (t) => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
receiveObjectOnlyFromJs({
|
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 tsfnAsyncCall(func: (...args: any[]) => any): Promise<void>
|
||||||
export function acceptThreadsafeFunction(func: (err: Error | null, value: number) => any): void
|
export function acceptThreadsafeFunction(func: (err: Error | null, value: number) => any): void
|
||||||
export function acceptThreadsafeFunctionFatal(func: (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 getBuffer(): Buffer
|
||||||
export function appendBuffer(buf: Buffer): Buffer
|
export function appendBuffer(buf: Buffer): Buffer
|
||||||
export function getEmptyBuffer(): Buffer
|
export function getEmptyBuffer(): Buffer
|
||||||
|
|
|
@ -116,3 +116,13 @@ pub fn accept_threadsafe_function_fatal(func: ThreadsafeFunction<u32, ErrorStrat
|
||||||
func.call(1, ThreadsafeFunctionCallMode::NonBlocking);
|
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