mirror of
https://github.com/napi-rs/napi-rs.git
synced 2025-12-08 19:56:07 +00:00
* Implement FromNapiValue trait as macro Code behavior should remain the same, with much less copy-pasting of the same code. Additionally, this commit adds a unit tests for test for FromNapiValue for tuple trait which appears to be currently missing. * Simplify macro arr_get Rewrite the macro to reduce the size of expanded code of the macro (from 4088 to 2429 lines). Although this is a minor change, this may help reduce the size of compiled library. * Refactor typegen Type::Path Removes the need for keeping mutable variable, as its only assigned once. * [API BREAKING] Update api for calling functions. This commit introduces new type FnArgs, that is created with the goal of distinguishing between calling JS function from rust with tuple as argument and calling with multiple arguments. Currently there is no possibility to add ToNapiValue value, as tuple is used to call callback functions with more than one argument from rust. With this change, callbacks with multiple arguments, should be called, with converting tuple of argument into FnArgs struct, either by calling into() on such tuple, or by creating FnArgs struct directly. * Add support for FnArgs when generating TS types Updated the macro for generating typescript types, to correctly handle FnArgs struct. This is now treated as passthrough type and generates the output from the type inside of FnArgs struct. * Implement ToNapiValue trait for tuple With the changes to callback calling API, it's now possible to safely add this change. This change allows to pass tuple from rust code to JS to match the existing FromNapiValue trait currently existing in the library.
103 lines
3.2 KiB
Rust
103 lines
3.2 KiB
Rust
use napi::{
|
|
bindgen_prelude::{FnArgs, Function},
|
|
CallContext, JsError, JsNull, JsObject, JsString, JsUnknown, Result,
|
|
};
|
|
|
|
#[js_function(1)]
|
|
pub fn call_function(ctx: CallContext) -> Result<JsNull> {
|
|
let js_func = ctx.get::<Function<FnArgs<(JsUnknown, JsUnknown)>>>(0)?;
|
|
let js_string_hello = ctx.env.create_string("hello".as_ref())?.into_unknown();
|
|
let js_string_world = ctx.env.create_string("world".as_ref())?.into_unknown();
|
|
|
|
js_func.call((js_string_hello, js_string_world).into())?;
|
|
|
|
ctx.env.get_null()
|
|
}
|
|
|
|
#[js_function(1)]
|
|
pub fn call_function_with_ref_arguments(ctx: CallContext) -> Result<JsNull> {
|
|
let js_func = ctx.get::<Function<FnArgs<(JsString, JsString)>>>(0)?;
|
|
let js_string_hello = ctx.env.create_string("hello".as_ref())?;
|
|
let js_string_world = ctx.env.create_string("world".as_ref())?;
|
|
|
|
js_func.call((js_string_hello, js_string_world).into())?;
|
|
|
|
ctx.env.get_null()
|
|
}
|
|
|
|
#[js_function(1)]
|
|
pub fn call_function_with_this(ctx: CallContext) -> Result<JsNull> {
|
|
let js_this: JsObject = ctx.this_unchecked();
|
|
let js_func = ctx.get::<Function<()>>(0)?;
|
|
|
|
js_func.apply(js_this, ())?;
|
|
|
|
ctx.env.get_null()
|
|
}
|
|
|
|
#[js_function(2)]
|
|
pub fn call_function_error(ctx: CallContext) -> Result<JsUnknown> {
|
|
let js_func = ctx.get::<Function<()>>(0)?;
|
|
let error_func = ctx.get::<Function>(1)?;
|
|
|
|
match js_func.call(()) {
|
|
Ok(v) => Ok(v),
|
|
Err(e) => error_func.call(JsError::from(e).into_unknown(*ctx.env)),
|
|
}
|
|
}
|
|
|
|
#[js_function(0)]
|
|
pub fn test_create_function_from_closure(ctx: CallContext) -> Result<Function<u32, String>> {
|
|
ctx
|
|
.env
|
|
.create_function_from_closure("functionFromClosure", move |ctx| {
|
|
if ctx.length() != 0 {
|
|
let args = ctx.arguments::<u32>()?;
|
|
let max = args.last().unwrap();
|
|
assert_eq!(*max, ctx.length() as u32 - 1);
|
|
}
|
|
Ok(format!("arguments length: {}", ctx.length()))
|
|
})
|
|
}
|
|
|
|
#[js_function(0)]
|
|
pub fn test_nest_create_function_from_closure(ctx: CallContext) -> Result<Function<(), ()>> {
|
|
ctx
|
|
.env
|
|
.create_function_from_closure("functionFromClosure", move |ctx| {
|
|
let obj = ctx.first_arg::<JsObject>()?;
|
|
let nest_func: Function<'_, (), ()> =
|
|
ctx
|
|
.env
|
|
.create_function_from_closure("nestFunctionFromClosure", move |_ctx| {
|
|
println!("nest function");
|
|
Ok(())
|
|
})?;
|
|
|
|
let on_handle =
|
|
obj.get_named_property::<Function<FnArgs<(String, Function<(), ()>)>, ()>>("on")?;
|
|
let handle_name = String::from("on");
|
|
on_handle.call((handle_name, nest_func).into())?;
|
|
Ok(())
|
|
})
|
|
}
|
|
|
|
pub fn register_js(exports: &mut JsObject) -> Result<()> {
|
|
exports.create_named_method("testCallFunction", call_function)?;
|
|
exports.create_named_method(
|
|
"testCallFunctionWithRefArguments",
|
|
call_function_with_ref_arguments,
|
|
)?;
|
|
exports.create_named_method("testCallFunctionWithThis", call_function_with_this)?;
|
|
exports.create_named_method("testCallFunctionError", call_function_error)?;
|
|
exports.create_named_method(
|
|
"testCreateFunctionFromClosure",
|
|
test_create_function_from_closure,
|
|
)?;
|
|
exports.create_named_method(
|
|
"testNestCreateFunctionFromClosure",
|
|
test_nest_create_function_from_closure,
|
|
)?;
|
|
Ok(())
|
|
}
|