Skip to content

Commit

Permalink
Move JsRest to be at the end only of arguments and add JsAll
Browse files Browse the repository at this point in the history
  • Loading branch information
hansl committed Apr 8, 2024
1 parent 3ea6baf commit 35fea4e
Show file tree
Hide file tree
Showing 2 changed files with 219 additions and 56 deletions.
156 changes: 112 additions & 44 deletions core/interop/src/into_js_function_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use std::cell::RefCell;
use boa_engine::{js_string, Context, JsError, NativeFunction, TryIntoJsResult};

use crate::private::IntoJsFunctionSealed;
use crate::{IntoJsFunctionCopied, TryFromJsArgument, UnsafeIntoJsFunction};
use crate::{IntoJsFunctionCopied, JsRest, TryFromJsArgument, UnsafeIntoJsFunction};

/// A token to represent the context argument in the function signature.
/// This should not be used directly and has no external meaning.
Expand All @@ -21,13 +21,27 @@ macro_rules! impl_into_js_function {
T: FnMut($($t,)*) -> R + 'static
{}

impl<$($t,)* R, T> IntoJsFunctionSealed<($($t,)* ContextArgToken), R> for T
impl<$($t,)* R, T> IntoJsFunctionSealed<($($t,)* ContextArgToken,), R> for T
where
$($t: TryFromJsArgument + 'static,)*
R: TryIntoJsResult,
T: FnMut($($t,)* &mut Context) -> R + 'static
{}

impl<$($t,)* R, T> IntoJsFunctionSealed<($($t,)* JsRest,), R> for T
where
$($t: TryFromJsArgument + 'static,)*
R: TryIntoJsResult,
T: FnMut($($t,)* JsRest) -> R + 'static
{}

impl<$($t,)* R, T> IntoJsFunctionSealed<($($t,)* JsRest, ContextArgToken), R> for T
where
$($t: TryFromJsArgument + 'static,)*
R: TryIntoJsResult,
T: FnMut($($t,)* JsRest, &mut Context) -> R + 'static
{}

impl<$($t,)* R, T> UnsafeIntoJsFunction<($($t,)*), R> for T
where
$($t: TryFromJsArgument + 'static,)*
Expand All @@ -44,7 +58,33 @@ macro_rules! impl_into_js_function {
let ($id, rest) = $t::try_from_js_argument(this, rest, ctx)?;
)*
match s.try_borrow_mut() {
Ok(mut r) => r( $($id),* ).try_into_js_result(ctx),
Ok(mut r) => r( $($id,)* ).try_into_js_result(ctx),
Err(_) => {
Err(JsError::from_opaque(js_string!("recursive calls to this function not supported").into()))
}
}
})
}
}
}

impl<$($t,)* R, T> UnsafeIntoJsFunction<($($t,)* JsRest,), R> for T
where
$($t: TryFromJsArgument + 'static,)*
R: TryIntoJsResult,
T: FnMut($($t,)* JsRest) -> R + 'static,
{
#[allow(unused_variables)]
unsafe fn into_js_function_unsafe(self, _context: &mut Context) -> NativeFunction {
let s = RefCell::new(self);
unsafe {
NativeFunction::from_closure(move |this, args, ctx| {
let rest = args;
$(
let ($id, rest) = $t::try_from_js_argument(this, rest, ctx)?;
)*
match s.try_borrow_mut() {
Ok(mut r) => r( $($id,)* rest.into() ).try_into_js_result(ctx),
Err(_) => {
Err(JsError::from_opaque(js_string!("recursive calls to this function not supported").into()))
}
Expand All @@ -54,7 +94,7 @@ macro_rules! impl_into_js_function {
}
}

impl<$($t,)* R, T> UnsafeIntoJsFunction<($($t,)* ContextArgToken), R> for T
impl<$($t,)* R, T> UnsafeIntoJsFunction<($($t,)* ContextArgToken,), R> for T
where
$($t: TryFromJsArgument + 'static,)*
R: TryIntoJsResult,
Expand All @@ -76,6 +116,28 @@ macro_rules! impl_into_js_function {
}
}

impl<$($t,)* R, T> UnsafeIntoJsFunction<($($t,)* JsRest, ContextArgToken), R> for T
where
$($t: TryFromJsArgument + 'static,)*
R: TryIntoJsResult,
T: FnMut($($t,)* JsRest, &mut Context) -> R + 'static,
{
#[allow(unused_variables)]
unsafe fn into_js_function_unsafe(self, _context: &mut Context) -> NativeFunction {
let s = RefCell::new(self);
unsafe {
NativeFunction::from_closure(move |this, args, ctx| {
let rest = args;
$(
let ($id, rest) = $t::try_from_js_argument(this, rest, ctx)?;
)*
let r = s.borrow_mut()( $($id,)* rest.into(), ctx);
r.try_into_js_result(ctx)
})
}
}
}

// Safe versions for `Fn(..) -> ...`.
impl<$($t,)* R, T> IntoJsFunctionCopied<($($t,)*), R> for T
where
Expand All @@ -92,18 +154,18 @@ macro_rules! impl_into_js_function {
$(
let ($id, rest) = $t::try_from_js_argument(this, rest, ctx)?;
)*
let r = s( $($id),* );
let r = s( $($id,)* );
r.try_into_js_result(ctx)
})
}
}
}

impl<$($t,)* R, T> IntoJsFunctionCopied<($($t,)* ContextArgToken), R> for T
impl<$($t,)* R, T> IntoJsFunctionCopied<($($t,)* JsRest,), R> for T
where
$($t: TryFromJsArgument + 'static,)*
R: TryIntoJsResult,
T: Fn($($t,)* &mut Context) -> R + 'static + Copy,
T: Fn($($t,)* JsRest) -> R + 'static + Copy,
{
#[allow(unused_variables)]
fn into_js_function_copied(self, _context: &mut Context) -> NativeFunction {
Expand All @@ -114,58 +176,64 @@ macro_rules! impl_into_js_function {
$(
let ($id, rest) = $t::try_from_js_argument(this, rest, ctx)?;
)*
let r = s( $($id,)* ctx);
let r = s( $($id,)* rest.into() );
r.try_into_js_result(ctx)
})
}
}
}
};
}

impl<R, T> IntoJsFunctionSealed<(), R> for T
where
R: TryIntoJsResult,
T: FnMut() -> R + 'static,
{
}

impl<R, T> UnsafeIntoJsFunction<(), R> for T
where
R: TryIntoJsResult,
T: FnMut() -> R + 'static,
{
unsafe fn into_js_function_unsafe(self, _context: &mut Context) -> NativeFunction {
let s = RefCell::new(self);
unsafe {
NativeFunction::from_closure(move |_this, _args, ctx| {
let r = s.borrow_mut()();
r.try_into_js_result(ctx)
})
impl<$($t,)* R, T> IntoJsFunctionCopied<($($t,)* ContextArgToken,), R> for T
where
$($t: TryFromJsArgument + 'static,)*
R: TryIntoJsResult,
T: Fn($($t,)* &mut Context) -> R + 'static + Copy,
{
#[allow(unused_variables)]
fn into_js_function_copied(self, _context: &mut Context) -> NativeFunction {
let s = self;
unsafe {
NativeFunction::from_closure(move |this, args, ctx| {
let rest = args;
$(
let ($id, rest) = $t::try_from_js_argument(this, rest, ctx)?;
)*
let r = s( $($id,)* ctx);
r.try_into_js_result(ctx)
})
}
}
}
}
}

impl<R, T> IntoJsFunctionCopied<(), R> for T
where
R: TryIntoJsResult,
T: Fn() -> R + 'static + Copy,
{
fn into_js_function_copied(self, _context: &mut Context) -> NativeFunction {
let s = self;
unsafe {
NativeFunction::from_closure(move |_this, _args, ctx| {
let r = s();
r.try_into_js_result(ctx)
})
impl<$($t,)* R, T> IntoJsFunctionCopied<($($t,)* JsRest, ContextArgToken), R> for T
where
$($t: TryFromJsArgument + 'static,)*
R: TryIntoJsResult,
T: Fn($($t,)* JsRest, &mut Context) -> R + 'static + Copy,
{
#[allow(unused_variables)]
fn into_js_function_copied(self, _context: &mut Context) -> NativeFunction {
let s = self;
unsafe {
NativeFunction::from_closure(move |this, args, ctx| {
let rest = args;
$(
let ($id, rest) = $t::try_from_js_argument(this, rest, ctx)?;
)*
let r = s( $($id,)* rest.into(), ctx);
r.try_into_js_result(ctx)
})
}
}
}
}
};
}

// Currently implemented up to 12 arguments. The empty argument list
// is implemented separately above.
// Consider that JsRest and JsThis are part of this list, but Context
// is not, as it is a special specialization of the template.
impl_into_js_function!();
impl_into_js_function!(a: A);
impl_into_js_function!(a: A, b: B);
impl_into_js_function!(a: A, b: B, c: C);
Expand Down
Loading

0 comments on commit 35fea4e

Please sign in to comment.