diff --git a/crates/neon-runtime/src/napi/fun.rs b/crates/neon-runtime/src/napi/fun.rs index f05ab51b5..297cfb7e3 100644 --- a/crates/neon-runtime/src/napi/fun.rs +++ b/crates/neon-runtime/src/napi/fun.rs @@ -32,7 +32,7 @@ pub unsafe fn call( fun: Local, this: Local, argc: i32, - argv: *mut c_void, + argv: *const c_void, ) -> bool { let status = napi::call_function( env, @@ -51,7 +51,7 @@ pub unsafe fn construct( env: Env, fun: Local, argc: i32, - argv: *mut c_void, + argv: *const c_void, ) -> bool { let status = napi::new_instance(env, fun, argc as usize, argv as *const _, out as *mut _); diff --git a/crates/neon-sys/src/lib.rs b/crates/neon-sys/src/lib.rs index d7910b618..149a83787 100644 --- a/crates/neon-sys/src/lib.rs +++ b/crates/neon-sys/src/lib.rs @@ -206,14 +206,14 @@ extern "C" { fun: Local, this: Local, argc: i32, - argv: *mut c_void, + argv: *const c_void, ) -> bool; pub fn Neon_Fun_Construct( out: &mut Local, isolate: Isolate, fun: Local, argc: i32, - argv: *mut c_void, + argv: *const c_void, ) -> bool; pub fn Neon_Mem_SameHandle(h1: Local, h2: Local) -> bool; diff --git a/src/context/mod.rs b/src/context/mod.rs index e9c405864..3601d0f4b 100644 --- a/src/context/mod.rs +++ b/src/context/mod.rs @@ -94,9 +94,8 @@ //! //! while !done { //! done = cx.execute_scoped(|mut cx| { // temporary scope -//! let args: Vec> = vec![]; -//! let obj = next.call(&mut cx, iterator, args)? // temporary object -//! .downcast_or_throw::(&mut cx)?; +//! let obj: Handle = next // temporary object +//! .call(&mut cx, iterator, ())?; //! let number = obj.get(&mut cx, "value")? // temporary number //! .downcast_or_throw::(&mut cx)? //! .value(&mut cx); diff --git a/src/event/event_handler.rs b/src/event/event_handler.rs index cb9e3b120..d7bbd196c 100644 --- a/src/event/event_handler.rs +++ b/src/event/event_handler.rs @@ -48,7 +48,7 @@ impl EventHandler { { self.schedule_with(move |cx, this, callback| { let args = arg_cb(cx); - let _result = callback.call(cx, this, args); + let _result = callback.exec(cx, this, args); }) } diff --git a/src/object/class/mod.rs b/src/object/class/mod.rs index dff27a59e..91fcfd514 100644 --- a/src/object/class/mod.rs +++ b/src/object/class/mod.rs @@ -11,7 +11,8 @@ use crate::context::{Context, Lock}; use crate::handle::{Handle, Managed}; use crate::object::{Object, This}; use crate::result::{JsResult, NeonResult, Throw}; -use crate::types::internal::{Callback, ValueInternal}; +use crate::types::function::Arguments; +use crate::types::private::{Callback, ValueInternal}; use crate::types::{build, JsFunction, JsValue, Value}; use neon_runtime; use neon_runtime::raw; @@ -103,10 +104,9 @@ pub trait Class: Managed + Any { } /// Convenience method for constructing new instances of this class without having to extract the constructor function. - fn new<'a, 'b, C: Context<'a>, A, AS>(cx: &mut C, args: AS) -> JsResult<'a, Self> + fn new<'a, 'b, C: Context<'a>, A>(cx: &mut C, args: A) -> JsResult<'a, Self> where - A: Value + 'b, - AS: IntoIterator>, + A: Arguments<'b>, { let constructor = Self::constructor(cx)?; constructor.construct(cx, args) diff --git a/src/types/binary.rs b/src/types/binary.rs index 98dba5d27..f9434fc53 100644 --- a/src/types/binary.rs +++ b/src/types/binary.rs @@ -4,7 +4,7 @@ use crate::context::internal::Env; use crate::context::{Context, Lock}; use crate::handle::Managed; use crate::result::JsResult; -use crate::types::internal::ValueInternal; +use crate::types::private::ValueInternal; use crate::types::{build, Object, Value}; use neon_runtime; use neon_runtime::raw; diff --git a/src/types/boxed.rs b/src/types/boxed.rs index d687e2064..f4378039f 100644 --- a/src/types/boxed.rs +++ b/src/types/boxed.rs @@ -8,7 +8,7 @@ use crate::context::internal::Env; use crate::context::{Context, FinalizeContext}; use crate::handle::{Handle, Managed}; use crate::object::Object; -use crate::types::internal::ValueInternal; +use crate::types::private::ValueInternal; use crate::types::Value; type BoxAny = Box; @@ -294,7 +294,7 @@ impl<'a, T: Send + 'static> Deref for JsBox { /// cx.number(self.1).upcast(), /// ]; /// -/// emit.call(cx, global, args).unwrap(); +/// emit.exec(cx, global, args).unwrap(); /// } /// } /// ``` diff --git a/src/types/buffer/types.rs b/src/types/buffer/types.rs index b24a23635..dc0bdcf6d 100644 --- a/src/types/buffer/types.rs +++ b/src/types/buffer/types.rs @@ -6,7 +6,7 @@ use neon_runtime::{raw, TypedArrayType}; use crate::context::{internal::Env, Context}; use crate::handle::{Handle, Managed}; use crate::result::{JsResult, Throw}; -use crate::types::{internal::ValueInternal, Object, Value}; +use crate::types::{private::ValueInternal, Object, Value}; use super::lock::{Ledger, Lock}; use super::{private, BorrowError, Ref, RefMut, TypedArray}; diff --git a/src/types/date.rs b/src/types/date.rs index 76c636f6e..0cd639aa7 100644 --- a/src/types/date.rs +++ b/src/types/date.rs @@ -1,4 +1,4 @@ -use super::{Value, ValueInternal}; +use super::{private::ValueInternal, Value}; use crate::context::internal::Env; use crate::context::Context; use crate::handle::{Handle, Managed}; diff --git a/src/types/error.rs b/src/types/error.rs index 3b89589af..3d3416644 100644 --- a/src/types/error.rs +++ b/src/types/error.rs @@ -8,7 +8,7 @@ use neon_runtime::raw; use crate::context::internal::Env; use crate::context::Context; use crate::result::{NeonResult, Throw}; -use crate::types::internal::ValueInternal; +use crate::types::private::ValueInternal; use crate::types::utf8::Utf8; use crate::types::{build, Handle, Managed, Object, Value}; diff --git a/src/types/function/mod.rs b/src/types/function/mod.rs new file mode 100644 index 000000000..1a4e9b605 --- /dev/null +++ b/src/types/function/mod.rs @@ -0,0 +1,140 @@ +//! Types and traits for working with JavaScript functions. + +use crate::handle::Handle; +use crate::types::Value; + +use smallvec::smallvec; + +pub(crate) mod private; + +/// The trait for specifying arguments for a function call. This trait is sealed and cannot +/// be implemented by types outside of the Neon crate. +/// +/// **Note:** This trait is implemented for tuples of up to 32 JavaScript values, +/// but for the sake of brevity, only tuples up to size 8 are shown in this documentation. +pub trait Arguments<'a>: private::ArgumentsInternal<'a> {} + +impl<'a, T: Value> private::ArgumentsInternal<'a> for Vec> { + fn into_args_vec(self) -> private::ArgsVec<'a> { + let mut args = smallvec![]; + for arg in self { + args.push(arg.upcast()); + } + args + } +} + +impl<'a, T: Value> Arguments<'a> for Vec> {} + +impl<'a, T: Value, const N: usize> private::ArgumentsInternal<'a> for [Handle<'a, T>; N] { + fn into_args_vec(self) -> private::ArgsVec<'a> { + let mut args = smallvec![]; + for arg in self { + args.push(arg.upcast()); + } + args + } +} + +impl<'a, T: Value, const N: usize> Arguments<'a> for [Handle<'a, T>; N] {} + +impl<'a> private::ArgumentsInternal<'a> for () { + fn into_args_vec(self) -> private::ArgsVec<'a> { + smallvec![] + } +} + +impl<'a> Arguments<'a> for () {} + +macro_rules! impl_arguments { + { + [ $(($tprefix:ident, $vprefix:ident), )* ]; + []; + } => {}; + + { + [ $(($tprefix:ident, $vprefix:ident), )* ]; + [ $(#[$attr1:meta])? ($tname1:ident, $vname1:ident), $($(#[$attrs:meta])? ($tnames:ident, $vnames:ident), )* ]; + } => { + $(#[$attr1])? + impl<'a, $($tprefix: Value, )* $tname1: Value> private::ArgumentsInternal<'a> for ($(Handle<'a, $tprefix>, )* Handle<'a, $tname1>, ) { + fn into_args_vec(self) -> private::ArgsVec<'a> { + let mut args = smallvec![]; + let ($($vprefix, )* $vname1, ) = self; + $(args.push($vprefix.upcast());)* + args.push($vname1.upcast()); + args + } + } + + $(#[$attr1])? + impl<'a, $($tprefix: Value, )* $tname1: Value> Arguments<'a> for ($(Handle<'a, $tprefix>, )* Handle<'a, $tname1>, ) {} + + impl_arguments! { + [ $(($tprefix, $vprefix), )* ($tname1, $vname1), ]; + [ $($(#[$attrs])? ($tnames, $vnames), )* ]; + } + }; +} + +impl_arguments! { + []; + [ + (V1, v1), + (V2, v2), + (V3, v3), + (V4, v4), + (V5, v5), + (V6, v6), + (V7, v7), + (V8, v8), + #[doc(hidden)] + (V9, v9), + #[doc(hidden)] + (V10, v10), + #[doc(hidden)] + (V11, v11), + #[doc(hidden)] + (V12, v12), + #[doc(hidden)] + (V13, v13), + #[doc(hidden)] + (V14, v14), + #[doc(hidden)] + (V15, v15), + #[doc(hidden)] + (V16, v16), + #[doc(hidden)] + (V17, v17), + #[doc(hidden)] + (V18, v18), + #[doc(hidden)] + (V19, v19), + #[doc(hidden)] + (V20, v20), + #[doc(hidden)] + (V21, v21), + #[doc(hidden)] + (V22, v22), + #[doc(hidden)] + (V23, v23), + #[doc(hidden)] + (V24, v24), + #[doc(hidden)] + (V25, v25), + #[doc(hidden)] + (V26, v26), + #[doc(hidden)] + (V27, v27), + #[doc(hidden)] + (V28, v28), + #[doc(hidden)] + (V29, v29), + #[doc(hidden)] + (V30, v30), + #[doc(hidden)] + (V31, v31), + #[doc(hidden)] + (V32, v32), + ]; +} diff --git a/src/types/function/private.rs b/src/types/function/private.rs new file mode 100644 index 000000000..e58d328fa --- /dev/null +++ b/src/types/function/private.rs @@ -0,0 +1,11 @@ +use crate::handle::Handle; +use crate::types::JsValue; + +use smallvec::SmallVec; + +pub type ArgsVec<'a> = SmallVec<[Handle<'a, JsValue>; 8]>; + +/// This type marks the `Arguments` trait as sealed. +pub trait ArgumentsInternal<'a> { + fn into_args_vec(self) -> ArgsVec<'a>; +} diff --git a/src/types/mod.rs b/src/types/mod.rs index 348fb8028..87b9778be 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -86,10 +86,13 @@ pub(crate) mod error; #[cfg(all(feature = "napi-1", feature = "promise-api"))] pub(crate) mod promise; -pub(crate) mod internal; +pub(crate) mod private; pub(crate) mod utf8; -use self::internal::{FunctionCallback, ValueInternal}; +pub mod function; + +use self::function::Arguments; +use self::private::{Callback, FunctionCallback}; use self::utf8::Utf8; use crate::context::internal::Env; use crate::context::{Context, FunctionContext}; @@ -97,10 +100,8 @@ use crate::handle::internal::SuperType; use crate::handle::{Handle, Managed}; use crate::object::{Object, This}; use crate::result::{JsResult, JsResultExt, NeonResult, Throw}; -use crate::types::internal::Callback; use neon_runtime; use neon_runtime::raw; -use smallvec::SmallVec; use std::fmt; use std::fmt::Debug; use std::marker::PhantomData; @@ -145,7 +146,7 @@ impl SuperType for JsObject { } /// The trait shared by all JavaScript values. -pub trait Value: ValueInternal { +pub trait Value: private::ValueInternal { fn to_string<'a, C: Context<'a>>(self, cx: &mut C) -> JsResult<'a, JsString> { let env = cx.env(); build(env, |out| unsafe { @@ -175,7 +176,7 @@ impl Managed for JsValue { } } -impl ValueInternal for JsValue { +impl private::ValueInternal for JsValue { fn name() -> String { "any".to_string() } @@ -261,7 +262,7 @@ unsafe impl This for JsUndefined { } } -impl ValueInternal for JsUndefined { +impl private::ValueInternal for JsUndefined { fn name() -> String { "undefined".to_string() } @@ -308,7 +309,7 @@ impl Managed for JsNull { } } -impl ValueInternal for JsNull { +impl private::ValueInternal for JsNull { fn name() -> String { "null".to_string() } @@ -360,7 +361,7 @@ impl Managed for JsBoolean { } } -impl ValueInternal for JsBoolean { +impl private::ValueInternal for JsBoolean { fn name() -> String { "boolean".to_string() } @@ -409,7 +410,7 @@ impl Managed for JsString { } } -impl ValueInternal for JsString { +impl private::ValueInternal for JsString { fn name() -> String { "string".to_string() } @@ -530,7 +531,7 @@ impl Managed for JsNumber { } } -impl ValueInternal for JsNumber { +impl private::ValueInternal for JsNumber { fn name() -> String { "number".to_string() } @@ -569,7 +570,7 @@ unsafe impl This for JsObject { } } -impl ValueInternal for JsObject { +impl private::ValueInternal for JsObject { fn name() -> String { "object".to_string() } @@ -669,7 +670,7 @@ impl Managed for JsArray { } } -impl ValueInternal for JsArray { +impl private::ValueInternal for JsArray { fn name() -> String { "Array".to_string() } @@ -694,19 +695,19 @@ impl Object for JsFunction {} // Maximum number of function arguments in V8. const V8_ARGC_LIMIT: usize = 65535; -unsafe fn prepare_call<'a, 'b, C: Context<'a>, A>( +fn prepare_call<'a, 'b, C: Context<'a>, A>( cx: &mut C, - args: &mut [Handle<'b, A>], -) -> NeonResult<(i32, *mut c_void)> + args: &[Handle<'b, A>], +) -> NeonResult<(i32, *const c_void)> where A: Value + 'b, { - let argv = args.as_mut_ptr(); + let argv = args.as_ptr(); let argc = args.len(); if argc > V8_ARGC_LIMIT { return cx.throw_range_error("too many arguments"); } - Ok((argc as i32, argv as *mut c_void)) + Ok((argc as i32, argv as *const c_void)) } impl JsFunction { @@ -729,37 +730,73 @@ impl JsFunction { } impl JsFunction { - pub fn call<'a, 'b, C: Context<'a>, T, A, AS>( + fn do_call<'a, 'b: 'a, C, T, A>( self, cx: &mut C, - this: Handle<'b, T>, - args: AS, - ) -> JsResult<'a, JsValue> + this: Handle<'a, T>, + args: &[Handle<'a, A>], + ) -> JsResult<'b, JsValue> where + C: Context<'b>, T: Value, - A: Value + 'b, - AS: IntoIterator>, + A: Value, { - let mut args = args.into_iter().collect::>(); - let (argc, argv) = unsafe { prepare_call(cx, &mut args) }?; + let (argc, argv) = prepare_call(cx, args)?; let env = cx.env().to_raw(); build(cx.env(), |out| unsafe { neon_runtime::fun::call(out, env, self.to_raw(), this.to_raw(), argc, argv) }) } - pub fn construct<'a, 'b, C: Context<'a>, A, AS>(self, cx: &mut C, args: AS) -> JsResult<'a, CL> + fn do_construct<'a, 'b: 'a, C, A>(self, cx: &mut C, args: &[Handle<'a, A>]) -> JsResult<'b, CL> where - A: Value + 'b, - AS: IntoIterator>, + C: Context<'b>, + A: Value, { - let mut args = args.into_iter().collect::>(); - let (argc, argv) = unsafe { prepare_call(cx, &mut args) }?; + let (argc, argv) = prepare_call(cx, args)?; let env = cx.env().to_raw(); build(cx.env(), |out| unsafe { neon_runtime::fun::construct(out, env, self.to_raw(), argc, argv) }) } + + pub fn call<'a, 'b, V: Value, C: Context<'a>, T, A>( + self, + cx: &mut C, + this: Handle<'b, T>, + args: A, + ) -> JsResult<'a, V> + where + V: Value, + T: Value, + A: Arguments<'b>, + { + let args = args.into_args_vec(); + self.do_call(cx, this, &args)?.downcast_or_throw::(cx) + } + + pub fn exec<'a, 'b, C: Context<'a>, T, A>( + self, + cx: &mut C, + this: Handle<'b, T>, + args: A, + ) -> NeonResult<()> + where + T: Value, + A: Arguments<'b>, + { + let args = args.into_args_vec(); + self.do_call(cx, this, &args)?; + Ok(()) + } + + pub fn construct<'a, 'b, C: Context<'a>, A>(self, cx: &mut C, args: A) -> JsResult<'a, CL> + where + A: Arguments<'b>, + { + let args = args.into_args_vec(); + self.do_construct(cx, &args) + } } impl Value for JsFunction {} @@ -777,7 +814,7 @@ impl Managed for JsFunction { } } -impl ValueInternal for JsFunction { +impl private::ValueInternal for JsFunction { fn name() -> String { "function".to_string() } diff --git a/src/types/internal.rs b/src/types/private.rs similarity index 100% rename from src/types/internal.rs rename to src/types/private.rs diff --git a/src/types/promise.rs b/src/types/promise.rs index d816f4b6c..b325fa033 100644 --- a/src/types/promise.rs +++ b/src/types/promise.rs @@ -12,7 +12,7 @@ use crate::handle::Managed; #[cfg(feature = "napi-6")] use crate::lifecycle::{DropData, InstanceData}; use crate::result::JsResult; -use crate::types::{Handle, Object, Value, ValueInternal}; +use crate::types::{private::ValueInternal, Handle, Object, Value}; #[cfg(feature = "channel-api")] use crate::{ context::TaskContext, diff --git a/test/dynamic/native/src/js/eventhandler.rs b/test/dynamic/native/src/js/eventhandler.rs index df612a6ae..253a2e5f0 100644 --- a/test/dynamic/native/src/js/eventhandler.rs +++ b/test/dynamic/native/src/js/eventhandler.rs @@ -112,7 +112,7 @@ declare_types! { thread::spawn(move || { cb.schedule_with(move |cx, this, callback| { let args : Vec> = vec![cx.string("number").upcast()]; - let result = callback.call(cx, this, args); + let result = callback.call::(cx, this, args); let cmd = match result { Ok(v) => { if let Ok(number) = v.downcast::() { @@ -127,8 +127,8 @@ declare_types! { }, Err(e) => format!("threw {}", e) }; - let args : Vec> = vec![cx.string(cmd).upcast()]; - let _result = callback.call(cx, this, args); + let cmd = cx.string(cmd); + let _result = callback.exec(cx, this, [cmd]); }); }); } diff --git a/test/dynamic/native/src/js/functions.rs b/test/dynamic/native/src/js/functions.rs index cafc80715..630f8114c 100644 --- a/test/dynamic/native/src/js/functions.rs +++ b/test/dynamic/native/src/js/functions.rs @@ -13,26 +13,20 @@ pub fn return_js_function(mut cx: FunctionContext) -> JsResult { pub fn call_js_function(mut cx: FunctionContext) -> JsResult { let f = cx.argument::(0)?; - let args: Vec> = vec![cx.number(16.0)]; + let arg = cx.number(16.0); let null = cx.null(); - f.call(&mut cx, null, args)? - .downcast::() - .or_throw(&mut cx) + f.call::(&mut cx, null, [arg]) } pub fn construct_js_function(mut cx: FunctionContext) -> JsResult { let f = cx.argument::(0)?; let zero = cx.number(0.0); - let o = f.construct(&mut cx, vec![zero])?; + let o = f.construct(&mut cx, [zero])?; let get_utc_full_year_method = o .get(&mut cx, "getUTCFullYear")? .downcast::() .or_throw(&mut cx)?; - let args: Vec> = vec![]; - get_utc_full_year_method - .call(&mut cx, o.upcast::(), args)? - .downcast::() - .or_throw(&mut cx) + get_utc_full_year_method.call::(&mut cx, o, ()) } trait CheckArgument<'a> { diff --git a/test/napi/src/js/functions.rs b/test/napi/src/js/functions.rs index 5a8bd819c..20728f94b 100644 --- a/test/napi/src/js/functions.rs +++ b/test/napi/src/js/functions.rs @@ -12,26 +12,20 @@ pub fn return_js_function(mut cx: FunctionContext) -> JsResult { pub fn call_js_function(mut cx: FunctionContext) -> JsResult { let f = cx.argument::(0)?; - let args: Vec> = vec![cx.number(16.0)]; + let arg = cx.number(16.0); let null = cx.null(); - f.call(&mut cx, null, args)? - .downcast::(&mut cx) - .or_throw(&mut cx) + f.call::(&mut cx, null, [arg]) } pub fn construct_js_function(mut cx: FunctionContext) -> JsResult { let f = cx.argument::(0)?; let zero = cx.number(0.0); - let o = f.construct(&mut cx, vec![zero])?; + let o = f.construct(&mut cx, [zero])?; let get_utc_full_year_method = o .get(&mut cx, "getUTCFullYear")? .downcast::(&mut cx) .or_throw(&mut cx)?; - let args: Vec> = vec![]; - get_utc_full_year_method - .call(&mut cx, o.upcast::(), args)? - .downcast::(&mut cx) - .or_throw(&mut cx) + get_utc_full_year_method.call::(&mut cx, o, ()) } trait CheckArgument<'a> { diff --git a/test/napi/src/js/threads.rs b/test/napi/src/js/threads.rs index 9e3de5702..e9edc76bf 100644 --- a/test/napi/src/js/threads.rs +++ b/test/napi/src/js/threads.rs @@ -21,9 +21,8 @@ pub fn thread_callback(mut cx: FunctionContext) -> JsResult { channel.send(move |mut cx| { let callback = callback.into_inner(&mut cx); let this = cx.undefined(); - let args = Vec::>::new(); - callback.call(&mut cx, this, args)?; + callback.exec(&mut cx, this, ())?; Ok(()) }) @@ -45,9 +44,9 @@ pub fn multi_threaded_callback(mut cx: FunctionContext) -> JsResult channel.send(move |mut cx| { let callback = callback.into_inner(&mut cx); let this = cx.undefined(); - let args = vec![cx.number(i as f64)]; + let i = cx.number(i as f64); - callback.call(&mut cx, this, args)?; + callback.exec(&mut cx, this, [i])?; Ok(()) }) @@ -78,9 +77,9 @@ impl AsyncGreeter { channel.send(|mut cx| { let callback = callback.into_inner(&mut cx); let this = cx.undefined(); - let args = vec![cx.string(greeting)]; + let greeting = cx.string(greeting); - callback.call(&mut cx, this, args)?; + callback.exec(&mut cx, this, [greeting])?; Ok(()) }) @@ -99,8 +98,7 @@ impl Finalize for AsyncGreeter { if let Some(shutdown) = shutdown { let shutdown = shutdown.into_inner(cx); let this = cx.undefined(); - let args = Vec::>::new(); - let _ = shutdown.call(cx, this, args); + let _ = shutdown.exec(cx, this, ()); } callback.drop(cx); @@ -163,9 +161,9 @@ pub fn drop_global_queue(mut cx: FunctionContext) -> JsResult { self.channel.send(|mut cx| { let callback = callback.into_inner(&mut cx); let this = cx.undefined(); - let args = vec![cx.undefined()]; + let undefined = cx.undefined(); - callback.call(&mut cx, this, args)?; + callback.exec(&mut cx, this, [undefined])?; Ok(()) }); @@ -207,8 +205,7 @@ pub fn channel_join(mut cx: FunctionContext) -> JsResult { get_message .into_inner(&mut cx) - .call::<_, _, JsValue, _>(&mut cx, this, [])? - .downcast_or_throw::(&mut cx) + .call::(&mut cx, this, ()) .map(|v| v.value(&mut cx)) }) .join() @@ -220,9 +217,11 @@ pub fn channel_join(mut cx: FunctionContext) -> JsResult { // Call back to JavaScript with the response channel.send(move |mut cx| { let this = cx.undefined(); - let args = [cx.string(response)]; + let response = cx.string(response); - callback.into_inner(&mut cx).call(&mut cx, this, args)?; + callback + .into_inner(&mut cx) + .exec(&mut cx, this, [response])?; Ok(()) });