#![allow(clippy::fn_to_numeric_cast)] use core::mem; use crate::convert::slices::WasmSlice; use crate::convert::RefFromWasmAbi; use crate::convert::{FromWasmAbi, IntoWasmAbi, ReturnWasmAbi, WasmAbi, WasmRet}; use crate::describe::{inform, WasmDescribe, FUNCTION}; use crate::throw_str; macro_rules! stack_closures { ($( ($cnt:tt $invoke:ident $invoke_mut:ident $($var:ident $arg1:ident $arg2:ident $arg3:ident $arg4:ident)*) )*) => ($( #[allow(coherence_leak_check)] impl<$($var,)* R> IntoWasmAbi for &'_ (dyn Fn($($var),*) -> R + '_) where $($var: FromWasmAbi,)* R: ReturnWasmAbi { type Abi = WasmSlice; fn into_abi(self) -> WasmSlice { unsafe { let (a, b): (usize, usize) = mem::transmute(self); WasmSlice { ptr: a as u32, len: b as u32 } } } } #[allow(non_snake_case)] unsafe extern "C" fn $invoke<$($var: FromWasmAbi,)* R: ReturnWasmAbi>( a: usize, b: usize, $( $arg1: <$var::Abi as WasmAbi>::Prim1, $arg2: <$var::Abi as WasmAbi>::Prim2, $arg3: <$var::Abi as WasmAbi>::Prim3, $arg4: <$var::Abi as WasmAbi>::Prim4, )* ) -> WasmRet { if a == 0 { throw_str("closure invoked after being dropped"); } // Scope all local variables before we call `return_abi` to // ensure they're all destroyed as `return_abi` may throw let ret = { let f: &dyn Fn($($var),*) -> R = mem::transmute((a, b)); $( let $var = <$var as FromWasmAbi>::from_abi($var::Abi::join($arg1, $arg2, $arg3, $arg4)); )* f($($var),*) }; ret.return_abi().into() } #[allow(coherence_leak_check)] impl<$($var,)* R> WasmDescribe for dyn Fn($($var),*) -> R + '_ where $($var: FromWasmAbi,)* R: ReturnWasmAbi { #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))] fn describe() { inform(FUNCTION); inform($invoke::<$($var,)* R> as usize as u32); inform($cnt); $(<$var as WasmDescribe>::describe();)* ::describe(); ::describe(); } } #[allow(coherence_leak_check)] impl<$($var,)* R> IntoWasmAbi for &'_ mut (dyn FnMut($($var),*) -> R + '_) where $($var: FromWasmAbi,)* R: ReturnWasmAbi { type Abi = WasmSlice; fn into_abi(self) -> WasmSlice { unsafe { let (a, b): (usize, usize) = mem::transmute(self); WasmSlice { ptr: a as u32, len: b as u32 } } } } #[allow(non_snake_case)] unsafe extern "C" fn $invoke_mut<$($var: FromWasmAbi,)* R: ReturnWasmAbi>( a: usize, b: usize, $( $arg1: <$var::Abi as WasmAbi>::Prim1, $arg2: <$var::Abi as WasmAbi>::Prim2, $arg3: <$var::Abi as WasmAbi>::Prim3, $arg4: <$var::Abi as WasmAbi>::Prim4, )* ) -> WasmRet { if a == 0 { throw_str("closure invoked recursively or after being dropped"); } // Scope all local variables before we call `return_abi` to // ensure they're all destroyed as `return_abi` may throw let ret = { let f: &mut dyn FnMut($($var),*) -> R = mem::transmute((a, b)); $( let $var = <$var as FromWasmAbi>::from_abi($var::Abi::join($arg1, $arg2, $arg3, $arg4)); )* f($($var),*) }; ret.return_abi().into() } #[allow(coherence_leak_check)] impl<$($var,)* R> WasmDescribe for dyn FnMut($($var),*) -> R + '_ where $($var: FromWasmAbi,)* R: ReturnWasmAbi { #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))] fn describe() { inform(FUNCTION); inform($invoke_mut::<$($var,)* R> as usize as u32); inform($cnt); $(<$var as WasmDescribe>::describe();)* ::describe(); ::describe(); } } )*) } stack_closures! { (0 invoke0 invoke0_mut) (1 invoke1 invoke1_mut A a1 a2 a3 a4) (2 invoke2 invoke2_mut A a1 a2 a3 a4 B b1 b2 b3 b4) (3 invoke3 invoke3_mut A a1 a2 a3 a4 B b1 b2 b3 b4 C c1 c2 c3 c4) (4 invoke4 invoke4_mut A a1 a2 a3 a4 B b1 b2 b3 b4 C c1 c2 c3 c4 D d1 d2 d3 d4) (5 invoke5 invoke5_mut A a1 a2 a3 a4 B b1 b2 b3 b4 C c1 c2 c3 c4 D d1 d2 d3 d4 E e1 e2 e3 e4) (6 invoke6 invoke6_mut A a1 a2 a3 a4 B b1 b2 b3 b4 C c1 c2 c3 c4 D d1 d2 d3 d4 E e1 e2 e3 e4 F f1 f2 f3 f4) (7 invoke7 invoke7_mut A a1 a2 a3 a4 B b1 b2 b3 b4 C c1 c2 c3 c4 D d1 d2 d3 d4 E e1 e2 e3 e4 F f1 f2 f3 f4 G g1 g2 g3 g4) (8 invoke8 invoke8_mut A a1 a2 a3 a4 B b1 b2 b3 b4 C c1 c2 c3 c4 D d1 d2 d3 d4 E e1 e2 e3 e4 F f1 f2 f3 f4 G g1 g2 g3 g4 H h1 h2 h3 h4) } impl IntoWasmAbi for &(dyn Fn(&A) -> R + '_) where A: RefFromWasmAbi, R: ReturnWasmAbi, { type Abi = WasmSlice; fn into_abi(self) -> WasmSlice { unsafe { let (a, b): (usize, usize) = mem::transmute(self); WasmSlice { ptr: a as u32, len: b as u32, } } } } #[allow(non_snake_case)] #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))] unsafe extern "C" fn invoke1_ref( a: usize, b: usize, arg1: ::Prim1, arg2: ::Prim2, arg3: ::Prim3, arg4: ::Prim4, ) -> WasmRet { if a == 0 { throw_str("closure invoked after being dropped"); } // Scope all local variables before we call `return_abi` to // ensure they're all destroyed as `return_abi` may throw let ret = { let f: &dyn Fn(&A) -> R = mem::transmute((a, b)); let arg = ::ref_from_abi(A::Abi::join(arg1, arg2, arg3, arg4)); f(&*arg) }; ret.return_abi().into() } impl WasmDescribe for dyn Fn(&A) -> R + '_ where A: RefFromWasmAbi, R: ReturnWasmAbi, { #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))] fn describe() { inform(FUNCTION); inform(invoke1_ref:: as usize as u32); inform(1); <&A as WasmDescribe>::describe(); ::describe(); ::describe(); } } impl IntoWasmAbi for &mut (dyn FnMut(&A) -> R + '_) where A: RefFromWasmAbi, R: ReturnWasmAbi, { type Abi = WasmSlice; fn into_abi(self) -> WasmSlice { unsafe { let (a, b): (usize, usize) = mem::transmute(self); WasmSlice { ptr: a as u32, len: b as u32, } } } } #[allow(non_snake_case)] #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))] unsafe extern "C" fn invoke1_mut_ref( a: usize, b: usize, arg1: ::Prim1, arg2: ::Prim2, arg3: ::Prim3, arg4: ::Prim4, ) -> WasmRet { if a == 0 { throw_str("closure invoked recursively or after being dropped"); } // Scope all local variables before we call `return_abi` to // ensure they're all destroyed as `return_abi` may throw let ret = { let f: &mut dyn FnMut(&A) -> R = mem::transmute((a, b)); let arg = ::ref_from_abi(A::Abi::join(arg1, arg2, arg3, arg4)); f(&*arg) }; ret.return_abi().into() } impl WasmDescribe for dyn FnMut(&A) -> R + '_ where A: RefFromWasmAbi, R: ReturnWasmAbi, { #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))] fn describe() { inform(FUNCTION); inform(invoke1_mut_ref:: as usize as u32); inform(1); <&A as WasmDescribe>::describe(); ::describe(); ::describe(); } }