use alloc::boxed::Box;
use alloc::vec::Vec;
use core::marker::PhantomData;
use crate::convert::RefFromBinaryDecode;
use crate::ipc::{DecodeError, DecodedData, EncodedData};
use crate::object_store::ObjectHandle;
use crate::value::JsValue;
use crate::{
Closure, IntoWasmClosure, IntoWasmClosureRef, IntoWasmClosureRefMut, WasmClosureFnOnce,
WasmClosureFnOnceAbort,
};
use super::{BinaryDecode, BinaryEncode, EncodeTypeDef, IntoClosure, TypeTag};
#[derive(Clone, Copy)]
pub(crate) enum CallbackPolicy {
RustOwned = 0,
JsOwned = 1,
JsOwnedOnce = 2,
}
pub struct CallbackKey<F: ?Sized>(ObjectHandle, CallbackPolicy, PhantomData<F>);
impl<F: ?Sized> CallbackKey<F> {
pub(crate) fn new(handle: ObjectHandle) -> Self {
Self::new_with_policy(handle, CallbackPolicy::JsOwned)
}
pub(crate) fn new_with_policy(handle: ObjectHandle, policy: CallbackPolicy) -> Self {
CallbackKey(handle, policy, PhantomData)
}
}
impl<F: ?Sized> BinaryEncode for CallbackKey<F> {
fn encode(self, encoder: &mut EncodedData) {
self.0.encode(encoder);
(self.1 as u32).encode(encoder);
}
}
impl<T: ?Sized> EncodeTypeDef for crate::ScopedClosure<'_, T> {
fn encode_type_def(buf: &mut Vec<u8>) {
JsValue::encode_type_def(buf);
}
}
macro_rules! decode_args {
($decoder:expr; [$first:ident, $($ty:ident,)*] => $body:expr) => {{
#[allow(non_snake_case)]
let $first = <$first as BinaryDecode>::decode($decoder)?;
decode_args!($decoder; [$($ty,)*] => $body);
}};
($decoder:expr; [] => $body:expr) => {{
$body;
return Ok(());
}};
}
macro_rules! callback_type_def_body {
($buf:expr; R = $R:ty; $($arg:ty),*) => {{
$buf.push(TypeTag::Callback as u8);
let mut count: u8 = 0;
$(
let _ = PhantomData::<$arg>;
count += 1;
)*
$buf.push(count);
$(<$arg as EncodeTypeDef>::encode_type_def($buf);)*
<$R as EncodeTypeDef>::encode_type_def($buf);
}};
($buf:expr; R = $R:ty; borrow_first; $($rest:ty),*) => {{
$buf.push(TypeTag::Callback as u8);
let mut count: u8 = 1;
$(
let _ = PhantomData::<$rest>;
count += 1;
)*
$buf.push(count);
$buf.push(TypeTag::BorrowedRef as u8);
$(<$rest as EncodeTypeDef>::encode_type_def($buf);)*
<$R as EncodeTypeDef>::encode_type_def($buf);
}};
}
macro_rules! impl_fnmut_stub {
($($arg:ident),*) => {
impl<R, $($arg,)*> EncodeTypeDef for CallbackKey<fn($($arg),*) -> R>
where
$($arg: EncodeTypeDef + 'static, )*
R: EncodeTypeDef + 'static,
{
#[allow(unused)]
fn encode_type_def(buf: &mut Vec<u8>) {
callback_type_def_body!(buf; R = R; $($arg),*);
}
}
impl<R, $($arg,)*> crate::WryWasmClosure<fn($($arg),*) -> R> for dyn FnMut($($arg),*) -> R
where
$($arg: BinaryDecode + EncodeTypeDef + 'static, )*
R: BinaryEncode + EncodeTypeDef + 'static,
{
#[allow(non_snake_case)]
#[allow(unused)]
fn into_js_closure(mut boxed: Box<Self>) -> crate::Closure<Self> {
crate::Closure::wrap_encode_decode_mut::<fn($($arg),*) -> R>(
move |decoder: &mut DecodedData, encoder: &mut EncodedData| {
decode_args!(decoder; [$($arg,)*] => {
let result = boxed($($arg),*);
result.encode(encoder);
});
},
)
}
}
impl<R, $($arg,)*> crate::WasmClosure for dyn FnMut($($arg),*) -> R
where
$($arg: 'static, )*
R: 'static,
{
type Static = dyn FnMut($($arg),*) -> R;
type AsMut = dyn FnMut($($arg),*) -> R;
}
impl<R, $($arg,)*> crate::WryWasmClosure<fn($($arg),*) -> R> for dyn Fn($($arg),*) -> R
where
$($arg: BinaryDecode + EncodeTypeDef + 'static, )*
R: BinaryEncode + EncodeTypeDef + 'static,
{
#[allow(non_snake_case)]
#[allow(unused)]
fn into_js_closure(boxed: Box<Self>) -> crate::Closure<Self> {
crate::Closure::wrap_encode_decode::<fn($($arg),*) -> R>(
move |decoder: &mut DecodedData, encoder: &mut EncodedData| {
decode_args!(decoder; [$($arg,)*] => {
let result = boxed($($arg),*);
result.encode(encoder);
});
}
)
}
}
impl<R, $($arg,)*> crate::WasmClosure for dyn Fn($($arg),*) -> R
where
$($arg: 'static, )*
R: 'static,
{
type Static = dyn Fn($($arg),*) -> R;
type AsMut = dyn FnMut($($arg),*) -> R;
}
impl<R, F, $($arg,)*> IntoClosure<fn($($arg),*) -> R, crate::Closure<dyn FnMut($($arg),*) -> R>> for F
where F: FnMut($($arg),*) -> R + 'static,
$($arg: BinaryDecode + EncodeTypeDef + 'static, )*
R: BinaryEncode + EncodeTypeDef + 'static,
{
#[allow(non_snake_case)]
#[allow(unused)]
fn into_closure(mut self) -> crate::Closure<dyn FnMut($($arg),*) -> R> {
crate::Closure::wrap_encode_decode_mut::<fn($($arg),*) -> R>(
move |decoder: &mut DecodedData, encoder: &mut EncodedData| {
decode_args!(decoder; [$($arg,)*] => {
let result = self($($arg),*);
result.encode(encoder);
});
},
)
}
}
impl<R, F, $($arg,)*> IntoClosure<fn($($arg),*) -> R, crate::Closure<dyn Fn($($arg),*) -> R>> for F
where F: Fn($($arg),*) -> R + 'static,
$($arg: BinaryDecode + EncodeTypeDef + 'static, )*
R: BinaryEncode + EncodeTypeDef + 'static,
{
#[allow(non_snake_case)]
#[allow(unused)]
fn into_closure(self) -> crate::Closure<dyn Fn($($arg),*) -> R> {
crate::Closure::wrap_encode_decode::<fn($($arg),*) -> R>(
move |decoder: &mut DecodedData, encoder: &mut EncodedData| {
decode_args!(decoder; [$($arg,)*] => {
let result = self($($arg),*);
result.encode(encoder);
});
},
)
}
}
impl<R, F, $($arg,)*> IntoWasmClosure<dyn FnMut($($arg),*) -> R> for F
where F: FnMut($($arg),*) -> R + 'static,
$($arg: BinaryDecode + EncodeTypeDef + 'static, )*
R: BinaryEncode + EncodeTypeDef + 'static,
{
fn into_closure(self) -> crate::Closure<dyn FnMut($($arg),*) -> R> {
<F as IntoClosure<fn($($arg),*) -> R, crate::Closure<dyn FnMut($($arg),*) -> R>>>::into_closure(self)
}
fn into_closure_box(self: Box<Self>) -> crate::Closure<dyn FnMut($($arg),*) -> R> {
<F as IntoWasmClosure<dyn FnMut($($arg),*) -> R>>::into_closure(*self)
}
}
impl<R, $($arg,)*> IntoWasmClosure<dyn FnMut($($arg),*) -> R> for dyn FnMut($($arg),*) -> R
where
$($arg: BinaryDecode + EncodeTypeDef + 'static, )*
R: BinaryEncode + EncodeTypeDef + 'static,
{
fn into_closure_box(self: Box<Self>) -> crate::Closure<dyn FnMut($($arg),*) -> R> {
<Self as crate::WryWasmClosure<fn($($arg),*) -> R>>::into_js_closure(self)
}
}
impl<R, F, $($arg,)*> IntoWasmClosure<dyn Fn($($arg),*) -> R> for F
where F: Fn($($arg),*) -> R + 'static,
$($arg: BinaryDecode + EncodeTypeDef + 'static, )*
R: BinaryEncode + EncodeTypeDef + 'static,
{
fn into_closure(self) -> crate::Closure<dyn Fn($($arg),*) -> R> {
<F as IntoClosure<fn($($arg),*) -> R, crate::Closure<dyn Fn($($arg),*) -> R>>>::into_closure(self)
}
fn into_closure_box(self: Box<Self>) -> crate::Closure<dyn Fn($($arg),*) -> R> {
<F as IntoWasmClosure<dyn Fn($($arg),*) -> R>>::into_closure(*self)
}
}
impl<R, $($arg,)*> IntoWasmClosure<dyn Fn($($arg),*) -> R> for dyn Fn($($arg),*) -> R
where
$($arg: BinaryDecode + EncodeTypeDef + 'static, )*
R: BinaryEncode + EncodeTypeDef + 'static,
{
fn into_closure_box(self: Box<Self>) -> crate::Closure<dyn Fn($($arg),*) -> R> {
<Self as crate::WryWasmClosure<fn($($arg),*) -> R>>::into_js_closure(self)
}
}
impl<R, F, $($arg,)*> IntoWasmClosureRef<dyn Fn($($arg),*) -> R> for F
where F: Fn($($arg),*) -> R,
$($arg: BinaryDecode + EncodeTypeDef + 'static, )*
R: BinaryEncode + EncodeTypeDef + 'static,
{
#[allow(non_snake_case)]
#[allow(unused)]
fn into_scoped_closure_ref<'a>(t: &'a Self) -> crate::ScopedClosure<'a, <dyn Fn($($arg),*) -> R as crate::WasmClosure>::Static> {
let t: &(dyn Fn($($arg),*) -> R) = t;
let ptr = t as *const dyn Fn($($arg),*) -> R;
let (data_ptr, vtable_ptr): (usize, usize) = unsafe { core::mem::transmute(ptr) };
let callback = crate::function::RustCallback::new_fn(
move |decoder: &mut DecodedData, encoder: &mut EncodedData| {
let ptr: *const dyn Fn($($arg),*) -> R = unsafe {
core::mem::transmute((data_ptr, vtable_ptr))
};
let f: &dyn Fn($($arg),*) -> R = unsafe { &*ptr };
decode_args!(decoder; [$($arg,)*] => {
let result = f($($arg),*);
result.encode(encoder);
});
},
);
let handle = crate::object_store::insert_object(callback);
let value = crate::__rt::wbg_cast::<CallbackKey<fn($($arg),*) -> R>, crate::JsValue>(
CallbackKey::new_with_policy(handle, CallbackPolicy::RustOwned),
);
crate::ScopedClosure {
_phantom: PhantomData,
callback: crate::closure::CallbackOwnership::Owned,
value,
}
}
}
impl<R, $($arg,)*> IntoWasmClosureRef<dyn Fn($($arg),*) -> R> for dyn Fn($($arg),*) -> R
where
$($arg: BinaryDecode + EncodeTypeDef + 'static, )*
R: BinaryEncode + EncodeTypeDef + 'static,
{
#[allow(non_snake_case)]
#[allow(unused)]
fn into_scoped_closure_ref<'a>(t: &'a Self) -> crate::ScopedClosure<'a, <dyn Fn($($arg),*) -> R as crate::WasmClosure>::Static> {
let ptr = t as *const dyn Fn($($arg),*) -> R;
let (data_ptr, vtable_ptr): (usize, usize) = unsafe { core::mem::transmute(ptr) };
let callback = crate::function::RustCallback::new_fn(
move |decoder: &mut DecodedData, encoder: &mut EncodedData| {
let ptr: *const dyn Fn($($arg),*) -> R = unsafe {
core::mem::transmute((data_ptr, vtable_ptr))
};
let f: &dyn Fn($($arg),*) -> R = unsafe { &*ptr };
decode_args!(decoder; [$($arg,)*] => {
let result = f($($arg),*);
result.encode(encoder);
});
},
);
let handle = crate::object_store::insert_object(callback);
let value = crate::__rt::wbg_cast::<CallbackKey<fn($($arg),*) -> R>, crate::JsValue>(
CallbackKey::new_with_policy(handle, CallbackPolicy::RustOwned),
);
crate::ScopedClosure {
_phantom: PhantomData,
callback: crate::closure::CallbackOwnership::Owned,
value,
}
}
}
impl<R, F, $($arg,)*> IntoWasmClosureRefMut<dyn FnMut($($arg),*) -> R> for F
where F: FnMut($($arg),*) -> R,
$($arg: BinaryDecode + EncodeTypeDef + 'static, )*
R: BinaryEncode + EncodeTypeDef + 'static,
{
#[allow(non_snake_case)]
#[allow(unused)]
fn into_scoped_closure_ref_mut<'a>(t: &'a mut Self) -> crate::ScopedClosure<'a, <dyn FnMut($($arg),*) -> R as crate::WasmClosure>::Static> {
let t: &mut dyn FnMut($($arg),*) -> R = t;
let ptr = t as *mut dyn FnMut($($arg),*) -> R;
let (data_ptr, vtable_ptr): (usize, usize) = unsafe { core::mem::transmute(ptr) };
let callback = crate::function::RustCallback::new_fn_mut(
move |decoder: &mut DecodedData, encoder: &mut EncodedData| {
let ptr: *mut dyn FnMut($($arg),*) -> R = unsafe {
core::mem::transmute((data_ptr, vtable_ptr))
};
let f: &mut dyn FnMut($($arg),*) -> R = unsafe { &mut *ptr };
decode_args!(decoder; [$($arg,)*] => {
let result = f($($arg),*);
result.encode(encoder);
});
},
);
let handle = crate::object_store::insert_object(callback);
let value = crate::__rt::wbg_cast::<CallbackKey<fn($($arg),*) -> R>, crate::JsValue>(
CallbackKey::new_with_policy(handle, CallbackPolicy::RustOwned),
);
crate::ScopedClosure {
_phantom: PhantomData,
callback: crate::closure::CallbackOwnership::Owned,
value,
}
}
}
impl<R, $($arg,)*> IntoWasmClosureRefMut<dyn FnMut($($arg),*) -> R> for dyn FnMut($($arg),*) -> R
where
$($arg: BinaryDecode + EncodeTypeDef + 'static, )*
R: BinaryEncode + EncodeTypeDef + 'static,
{
#[allow(non_snake_case)]
#[allow(unused)]
fn into_scoped_closure_ref_mut<'a>(t: &'a mut Self) -> crate::ScopedClosure<'a, <dyn FnMut($($arg),*) -> R as crate::WasmClosure>::Static> {
let ptr = t as *mut dyn FnMut($($arg),*) -> R;
let (data_ptr, vtable_ptr): (usize, usize) = unsafe { core::mem::transmute(ptr) };
let callback = crate::function::RustCallback::new_fn_mut(
move |decoder: &mut DecodedData, encoder: &mut EncodedData| {
let ptr: *mut dyn FnMut($($arg),*) -> R = unsafe {
core::mem::transmute((data_ptr, vtable_ptr))
};
let f: &mut dyn FnMut($($arg),*) -> R = unsafe { &mut *ptr };
decode_args!(decoder; [$($arg,)*] => {
let result = f($($arg),*);
result.encode(encoder);
});
},
);
let handle = crate::object_store::insert_object(callback);
let value = crate::__rt::wbg_cast::<CallbackKey<fn($($arg),*) -> R>, crate::JsValue>(
CallbackKey::new_with_policy(handle, CallbackPolicy::RustOwned),
);
crate::ScopedClosure {
_phantom: PhantomData,
callback: crate::closure::CallbackOwnership::Owned,
value,
}
}
}
};
}
macro_rules! impl_closure_ref_binary_encode {
(
impl ($($self_ty:tt)*) via *mut dyn FnMut, $ctor:ident;
$($arg:ident),*
) => {
impl<R, $($arg,)*> BinaryEncode for $($self_ty)*
where
$($arg: BinaryDecode + EncodeTypeDef + 'static, )*
R: BinaryEncode + EncodeTypeDef + 'static,
{
#[allow(non_snake_case)]
#[allow(unused)]
fn encode(self, encoder: &mut EncodedData) {
encoder.mark_needs_flush();
let ptr = self as *mut dyn FnMut($($arg),*) -> R;
let (data_ptr, vtable_ptr): (usize, usize) = unsafe { core::mem::transmute(ptr) };
let callback = crate::function::RustCallback::$ctor(
move |decoder: &mut DecodedData, encoder: &mut EncodedData| {
let ptr: *mut dyn FnMut($($arg),*) -> R = unsafe {
core::mem::transmute((data_ptr, vtable_ptr))
};
let f: &mut dyn FnMut($($arg),*) -> R = unsafe { &mut *ptr };
$(let $arg = <$arg as BinaryDecode>::decode(decoder)?;)*
let result = f($($arg),*);
result.encode(encoder);
Ok(())
},
);
let handle = crate::object_store::insert_object(callback);
let key: CallbackKey<fn($($arg),*) -> R> =
CallbackKey::new_with_policy(handle, CallbackPolicy::RustOwned);
key.encode(encoder);
crate::batch::queue_rust_object_drop(handle);
}
}
};
(
impl ($($self_ty:tt)*) via *const dyn Fn, $ctor:ident;
$($arg:ident),*
) => {
impl<R, $($arg,)*> BinaryEncode for $($self_ty)*
where
$($arg: BinaryDecode + EncodeTypeDef + 'static, )*
R: BinaryEncode + EncodeTypeDef + 'static,
{
#[allow(non_snake_case)]
#[allow(unused)]
fn encode(self, encoder: &mut EncodedData) {
encoder.mark_needs_flush();
let ptr = self as *const dyn Fn($($arg),*) -> R;
let (data_ptr, vtable_ptr): (usize, usize) = unsafe { core::mem::transmute(ptr) };
let callback = crate::function::RustCallback::$ctor(
move |decoder: &mut DecodedData, encoder: &mut EncodedData| {
let ptr: *const dyn Fn($($arg),*) -> R = unsafe {
core::mem::transmute((data_ptr, vtable_ptr))
};
let f: &dyn Fn($($arg),*) -> R = unsafe { &*ptr };
$(let $arg = <$arg as BinaryDecode>::decode(decoder)?;)*
let result = f($($arg),*);
result.encode(encoder);
Ok(())
},
);
let handle = crate::object_store::insert_object(callback);
let key: CallbackKey<fn($($arg),*) -> R> =
CallbackKey::new_with_policy(handle, CallbackPolicy::RustOwned);
key.encode(encoder);
crate::batch::queue_rust_object_drop(handle);
}
}
};
}
macro_rules! impl_closure_ref_encode {
($($arg:ident),*) => {
impl<R, $($arg,)*> EncodeTypeDef for &mut dyn FnMut($($arg),*) -> R
where
$($arg: EncodeTypeDef + 'static, )*
R: EncodeTypeDef + 'static,
{
#[allow(unused)]
fn encode_type_def(buf: &mut Vec<u8>) {
callback_type_def_body!(buf; R = R; $($arg),*);
}
}
impl_closure_ref_binary_encode!(
impl (&mut dyn FnMut($($arg),*) -> R) via *mut dyn FnMut, new_fn_mut;
$($arg),*
);
impl<R, $($arg,)*> EncodeTypeDef for &dyn Fn($($arg),*) -> R
where
$($arg: EncodeTypeDef + 'static, )*
R: EncodeTypeDef + 'static,
{
#[allow(unused)]
fn encode_type_def(buf: &mut Vec<u8>) {
callback_type_def_body!(buf; R = R; $($arg),*);
}
}
impl_closure_ref_binary_encode!(
impl (&dyn Fn($($arg),*) -> R) via *const dyn Fn, new_fn;
$($arg),*
);
impl<R, $($arg,)*> EncodeTypeDef for &mut dyn Fn($($arg),*) -> R
where
$($arg: EncodeTypeDef + 'static, )*
R: EncodeTypeDef + 'static,
{
#[allow(unused)]
fn encode_type_def(buf: &mut Vec<u8>) {
callback_type_def_body!(buf; R = R; $($arg),*);
}
}
impl_closure_ref_binary_encode!(
impl (&mut dyn Fn($($arg),*) -> R) via *const dyn Fn, new_fn;
$($arg),*
);
};
}
impl_closure_ref_encode!();
impl_closure_ref_encode!(A1);
impl_closure_ref_encode!(A1, A2);
impl_closure_ref_encode!(A1, A2, A3);
impl_closure_ref_encode!(A1, A2, A3, A4);
impl_closure_ref_encode!(A1, A2, A3, A4, A5);
impl_closure_ref_encode!(A1, A2, A3, A4, A5, A6);
impl_closure_ref_encode!(A1, A2, A3, A4, A5, A6, A7);
impl_fnmut_stub!();
impl_fnmut_stub!(A1);
impl_fnmut_stub!(A1, A2);
impl_fnmut_stub!(A1, A2, A3);
impl_fnmut_stub!(A1, A2, A3, A4);
impl_fnmut_stub!(A1, A2, A3, A4, A5);
impl_fnmut_stub!(A1, A2, A3, A4, A5, A6);
impl_fnmut_stub!(A1, A2, A3, A4, A5, A6, A7);
impl_fnmut_stub!(A1, A2, A3, A4, A5, A6, A7, A8);
pub struct BorrowedFirstArg;
macro_rules! impl_fnmut_stub_ref {
($first:ident $(, $rest:ident)*) => {
#[allow(coherence_leak_check)]
impl<R, $first, $($rest,)*> EncodeTypeDef for CallbackKey<fn(&$first, $($rest),*) -> R>
where
$first: EncodeTypeDef + 'static,
$($rest: EncodeTypeDef + 'static, )*
R: EncodeTypeDef + 'static,
{
#[allow(unused)]
fn encode_type_def(buf: &mut Vec<u8>) {
callback_type_def_body!(buf; R = R; borrow_first; $($rest),*);
}
}
impl<R, $first, $($rest,)*> crate::WryWasmClosure<(BorrowedFirstArg, fn(&$first, $($rest),*) -> R)> for dyn FnMut(&$first, $($rest),*) -> R
where
$first: RefFromBinaryDecode + EncodeTypeDef + 'static,
$($rest: BinaryDecode + EncodeTypeDef + 'static,)*
R: BinaryEncode + EncodeTypeDef + 'static,
{
#[allow(non_snake_case)]
#[allow(unused)]
fn into_js_closure(mut boxed: Box<Self>) -> crate::Closure<Self> {
crate::Closure::wrap_encode_decode_mut::<fn(&$first, $($rest),*) -> R>(
move |decoder: &mut DecodedData, encoder: &mut EncodedData| {
let anchor = <$first as RefFromBinaryDecode>::ref_decode(decoder)?;
$(let $rest = <$rest as BinaryDecode>::decode(decoder)?;)*
let result = boxed(&*anchor, $($rest),*);
result.encode(encoder);
Ok(())
},
)
}
}
#[allow(coherence_leak_check)]
impl<R, $first, $($rest,)*> crate::WasmClosure for dyn FnMut(&$first, $($rest),*) -> R
where
$first: 'static,
$($rest: 'static,)*
R: 'static,
{
type Static = dyn FnMut(&$first, $($rest),*) -> R;
type AsMut = dyn FnMut(&$first, $($rest),*) -> R;
}
impl<R, $first, $($rest,)*> crate::WryWasmClosure<(BorrowedFirstArg, fn(&$first, $($rest),*) -> R)> for dyn Fn(&$first, $($rest),*) -> R
where
$first: RefFromBinaryDecode + EncodeTypeDef + 'static,
$($rest: BinaryDecode + EncodeTypeDef + 'static,)*
R: BinaryEncode + EncodeTypeDef + 'static,
{
#[allow(non_snake_case)]
#[allow(unused)]
fn into_js_closure(boxed: Box<Self>) -> crate::Closure<Self> {
crate::Closure::wrap_encode_decode::<fn(&$first, $($rest),*) -> R>(
move |decoder: &mut DecodedData, encoder: &mut EncodedData| {
let anchor = <$first as RefFromBinaryDecode>::ref_decode(decoder)?;
$(let $rest = <$rest as BinaryDecode>::decode(decoder)?;)*
let result = boxed(&*anchor, $($rest),*);
result.encode(encoder);
Ok(())
},
)
}
}
#[allow(coherence_leak_check)]
impl<R, $first, $($rest,)*> crate::WasmClosure for dyn Fn(&$first, $($rest),*) -> R
where
$first: 'static,
$($rest: 'static,)*
R: 'static,
{
type Static = dyn Fn(&$first, $($rest),*) -> R;
type AsMut = dyn FnMut(&$first, $($rest),*) -> R;
}
impl<R, F, $first, $($rest,)*> IntoClosure<(BorrowedFirstArg, fn(&$first, $($rest),*) -> R), crate::Closure<dyn FnMut(&$first, $($rest),*) -> R>> for F
where F: FnMut(&$first, $($rest),*) -> R + 'static,
$first: RefFromBinaryDecode + EncodeTypeDef + 'static,
$($rest: BinaryDecode + EncodeTypeDef + 'static,)*
R: BinaryEncode + EncodeTypeDef + 'static,
{
#[allow(non_snake_case)]
#[allow(unused)]
fn into_closure(mut self) -> crate::Closure<dyn FnMut(&$first, $($rest),*) -> R> {
crate::Closure::wrap_encode_decode_mut::<fn(&$first, $($rest),*) -> R>(
move |decoder: &mut DecodedData, encoder: &mut EncodedData| {
let anchor = <$first as RefFromBinaryDecode>::ref_decode(decoder)?;
$(let $rest = <$rest as BinaryDecode>::decode(decoder)?;)*
let result = self(&*anchor, $($rest),*);
result.encode(encoder);
Ok(())
},
)
}
}
impl<R, F, $first, $($rest,)*> IntoClosure<(BorrowedFirstArg, fn(&$first, $($rest),*) -> R), crate::Closure<dyn Fn(&$first, $($rest),*) -> R>> for F
where F: Fn(&$first, $($rest),*) -> R + 'static,
$first: RefFromBinaryDecode + EncodeTypeDef + 'static,
$($rest: BinaryDecode + EncodeTypeDef + 'static,)*
R: BinaryEncode + EncodeTypeDef + 'static,
{
#[allow(non_snake_case)]
#[allow(unused)]
fn into_closure(self) -> crate::Closure<dyn Fn(&$first, $($rest),*) -> R> {
crate::Closure::wrap_encode_decode::<fn(&$first, $($rest),*) -> R>(
move |decoder: &mut DecodedData, encoder: &mut EncodedData| {
let anchor = <$first as RefFromBinaryDecode>::ref_decode(decoder)?;
$(let $rest = <$rest as BinaryDecode>::decode(decoder)?;)*
let result = self(&*anchor, $($rest),*);
result.encode(encoder);
Ok(())
},
)
}
}
#[allow(coherence_leak_check)]
impl<R, F, $first, $($rest,)*> IntoWasmClosure<dyn FnMut(&$first, $($rest),*) -> R> for F
where F: FnMut(&$first, $($rest),*) -> R + 'static,
$first: RefFromBinaryDecode + EncodeTypeDef + 'static,
$($rest: BinaryDecode + EncodeTypeDef + 'static,)*
R: BinaryEncode + EncodeTypeDef + 'static,
{
fn into_closure(self) -> crate::Closure<dyn FnMut(&$first, $($rest),*) -> R> {
<F as IntoClosure<(BorrowedFirstArg, fn(&$first, $($rest),*) -> R), crate::Closure<dyn FnMut(&$first, $($rest),*) -> R>>>::into_closure(self)
}
fn into_closure_box(self: Box<Self>) -> crate::Closure<dyn FnMut(&$first, $($rest),*) -> R> {
<F as IntoWasmClosure<dyn FnMut(&$first, $($rest),*) -> R>>::into_closure(*self)
}
}
#[allow(coherence_leak_check)]
impl<R, $first, $($rest,)*> IntoWasmClosure<dyn FnMut(&$first, $($rest),*) -> R> for dyn FnMut(&$first, $($rest),*) -> R
where
$first: RefFromBinaryDecode + EncodeTypeDef + 'static,
$($rest: BinaryDecode + EncodeTypeDef + 'static,)*
R: BinaryEncode + EncodeTypeDef + 'static,
{
fn into_closure_box(self: Box<Self>) -> crate::Closure<dyn FnMut(&$first, $($rest),*) -> R> {
<Self as crate::WryWasmClosure<(BorrowedFirstArg, fn(&$first, $($rest),*) -> R)>>::into_js_closure(self)
}
}
#[allow(coherence_leak_check)]
impl<R, F, $first, $($rest,)*> IntoWasmClosure<dyn Fn(&$first, $($rest),*) -> R> for F
where F: Fn(&$first, $($rest),*) -> R + 'static,
$first: RefFromBinaryDecode + EncodeTypeDef + 'static,
$($rest: BinaryDecode + EncodeTypeDef + 'static,)*
R: BinaryEncode + EncodeTypeDef + 'static,
{
fn into_closure(self) -> crate::Closure<dyn Fn(&$first, $($rest),*) -> R> {
<F as IntoClosure<(BorrowedFirstArg, fn(&$first, $($rest),*) -> R), crate::Closure<dyn Fn(&$first, $($rest),*) -> R>>>::into_closure(self)
}
fn into_closure_box(self: Box<Self>) -> crate::Closure<dyn Fn(&$first, $($rest),*) -> R> {
<F as IntoWasmClosure<dyn Fn(&$first, $($rest),*) -> R>>::into_closure(*self)
}
}
#[allow(coherence_leak_check)]
impl<R, $first, $($rest,)*> IntoWasmClosure<dyn Fn(&$first, $($rest),*) -> R> for dyn Fn(&$first, $($rest),*) -> R
where
$first: RefFromBinaryDecode + EncodeTypeDef + 'static,
$($rest: BinaryDecode + EncodeTypeDef + 'static,)*
R: BinaryEncode + EncodeTypeDef + 'static,
{
fn into_closure_box(self: Box<Self>) -> crate::Closure<dyn Fn(&$first, $($rest),*) -> R> {
<Self as crate::WryWasmClosure<(BorrowedFirstArg, fn(&$first, $($rest),*) -> R)>>::into_js_closure(self)
}
}
};
}
impl_fnmut_stub_ref!(A1);
impl_fnmut_stub_ref!(A1, A2);
impl_fnmut_stub_ref!(A1, A2, A3);
impl_fnmut_stub_ref!(A1, A2, A3, A4);
impl_fnmut_stub_ref!(A1, A2, A3, A4, A5);
impl_fnmut_stub_ref!(A1, A2, A3, A4, A5, A6);
impl_fnmut_stub_ref!(A1, A2, A3, A4, A5, A6, A7);
impl_fnmut_stub_ref!(A1, A2, A3, A4, A5, A6, A7, A8);
macro_rules! impl_fn_once {
($($arg:ident),*) => {
impl<R, F, $($arg,)*> WasmClosureFnOnce<dyn FnMut($($arg),*) -> R, fn($($arg),*) -> R, R> for F
where
F: FnOnce($($arg),*) -> R + 'static,
$($arg: BinaryDecode + EncodeTypeDef + 'static,)*
R: BinaryEncode + EncodeTypeDef + 'static,
{
#[allow(non_snake_case)]
#[allow(unused_variables)]
fn into_closure(self) -> Closure<dyn FnMut($($arg),*) -> R> {
let mut me = Some(self);
crate::Closure::wrap_once_encode_decode_mut::<fn($($arg),*) -> R>(
move |decoder: &mut DecodedData, encoder: &mut EncodedData| {
let f = me.take().expect("FnOnce closure called more than once");
decode_args!(decoder; [$($arg,)*] => {
let result = f($($arg),*);
result.encode(encoder);
});
},
)
}
}
impl<R, F, $($arg,)*> WasmClosureFnOnceAbort<dyn FnMut($($arg),*) -> R, fn($($arg),*) -> R, R> for F
where
F: FnOnce($($arg),*) -> R + 'static,
$($arg: BinaryDecode + EncodeTypeDef + 'static,)*
R: BinaryEncode + EncodeTypeDef + 'static,
{
#[allow(non_snake_case)]
#[allow(unused_variables)]
fn into_closure(self) -> Closure<dyn FnMut($($arg),*) -> R> {
<F as WasmClosureFnOnce<dyn FnMut($($arg),*) -> R, fn($($arg),*) -> R, R>>::into_closure(self)
}
}
};
}
impl_fn_once!();
impl_fn_once!(A1);
impl_fn_once!(A1, A2);
impl_fn_once!(A1, A2, A3);
impl_fn_once!(A1, A2, A3, A4);
impl_fn_once!(A1, A2, A3, A4, A5);
impl_fn_once!(A1, A2, A3, A4, A5, A6);
impl_fn_once!(A1, A2, A3, A4, A5, A6, A7);
impl_fn_once!(A1, A2, A3, A4, A5, A6, A7, A8);
macro_rules! impl_fn_once_ref {
($first:ident $(, $rest:ident)*) => {
impl<R, F, $first, $($rest,)*> WasmClosureFnOnce<dyn FnMut(&$first, $($rest),*) -> R, (BorrowedFirstArg, fn(&$first, $($rest),*) -> R), R> for F
where
F: FnOnce(&$first, $($rest),*) -> R + 'static,
$first: RefFromBinaryDecode + EncodeTypeDef + 'static,
$($rest: BinaryDecode + EncodeTypeDef + 'static,)*
R: BinaryEncode + EncodeTypeDef + 'static,
{
#[allow(non_snake_case)]
#[allow(unused_variables)]
fn into_closure(self) -> Closure<dyn FnMut(&$first, $($rest),*) -> R> {
let mut me = Some(self);
crate::Closure::wrap_once_encode_decode_mut::<fn(&$first, $($rest),*) -> R>(
move |decoder: &mut DecodedData, encoder: &mut EncodedData| {
let f = me.take().expect("FnOnce closure called more than once");
let anchor = <$first as RefFromBinaryDecode>::ref_decode(decoder)?;
$(let $rest = <$rest as BinaryDecode>::decode(decoder)?;)*
let result = f(&*anchor, $($rest),*);
result.encode(encoder);
Ok(())
},
)
}
}
impl<R, F, $first, $($rest,)*> WasmClosureFnOnceAbort<dyn FnMut(&$first, $($rest),*) -> R, (BorrowedFirstArg, fn(&$first, $($rest),*) -> R), R> for F
where
F: FnOnce(&$first, $($rest),*) -> R + 'static,
$first: RefFromBinaryDecode + EncodeTypeDef + 'static,
$($rest: BinaryDecode + EncodeTypeDef + 'static,)*
R: BinaryEncode + EncodeTypeDef + 'static,
{
#[allow(non_snake_case)]
#[allow(unused_variables)]
fn into_closure(self) -> Closure<dyn FnMut(&$first, $($rest),*) -> R> {
<F as WasmClosureFnOnce<dyn FnMut(&$first, $($rest),*) -> R, (BorrowedFirstArg, fn(&$first, $($rest),*) -> R), R>>::into_closure(self)
}
}
};
}
impl_fn_once_ref!(A1);
impl_fn_once_ref!(A1, A2);
impl_fn_once_ref!(A1, A2, A3);
impl_fn_once_ref!(A1, A2, A3, A4);
impl_fn_once_ref!(A1, A2, A3, A4, A5);
impl_fn_once_ref!(A1, A2, A3, A4, A5, A6);
impl_fn_once_ref!(A1, A2, A3, A4, A5, A6, A7);
impl_fn_once_ref!(A1, A2, A3, A4, A5, A6, A7, A8);
impl<F: ?Sized> BinaryDecode for crate::Closure<F> {
fn decode(decoder: &mut DecodedData) -> Result<Self, DecodeError> {
let value = <crate::JsValue as BinaryDecode>::decode(decoder)?;
Ok(Self {
_phantom: PhantomData,
callback: crate::closure::CallbackOwnership::None,
value,
})
}
}
impl<F: ?Sized> BinaryEncode for crate::Closure<F> {
fn encode(mut self, encoder: &mut EncodedData) {
if self.callback.needs_flush() {
encoder.mark_needs_flush();
}
self.callback.detach();
(&self.value).encode(encoder);
}
}
impl<F: ?Sized> BinaryEncode for &crate::ScopedClosure<'_, F> {
fn encode(self, encoder: &mut EncodedData) {
if self.callback.needs_flush() {
encoder.mark_needs_flush();
}
(&self.value).encode(encoder);
}
}