1#![allow(clippy::fn_to_numeric_cast)]
2
3use core::mem;
4
5use crate::convert::slices::WasmSlice;
6use crate::convert::RefFromWasmAbi;
7use crate::convert::{FromWasmAbi, IntoWasmAbi, ReturnWasmAbi, WasmAbi, WasmRet};
8use crate::describe::{inform, WasmDescribe, FUNCTION};
9use crate::throw_str;
10
11macro_rules! stack_closures {
12 ($( ($cnt:tt $invoke:ident $invoke_mut:ident $($var:ident $arg1:ident $arg2:ident $arg3:ident $arg4:ident)*) )*) => ($(
13 #[allow(coherence_leak_check)]
14 impl<$($var,)* R> IntoWasmAbi for &'_ (dyn Fn($($var),*) -> R + '_)
15 where $($var: FromWasmAbi,)*
16 R: ReturnWasmAbi
17 {
18 type Abi = WasmSlice;
19
20 fn into_abi(self) -> WasmSlice {
21 unsafe {
22 let (a, b): (usize, usize) = mem::transmute(self);
23 WasmSlice { ptr: a as u32, len: b as u32 }
24 }
25 }
26 }
27
28 #[allow(non_snake_case)]
29 unsafe extern "C" fn $invoke<$($var: FromWasmAbi,)* R: ReturnWasmAbi>(
30 a: usize,
31 b: usize,
32 $(
33 $arg1: <$var::Abi as WasmAbi>::Prim1,
34 $arg2: <$var::Abi as WasmAbi>::Prim2,
35 $arg3: <$var::Abi as WasmAbi>::Prim3,
36 $arg4: <$var::Abi as WasmAbi>::Prim4,
37 )*
38 ) -> WasmRet<R::Abi> {
39 if a == 0 {
40 throw_str("closure invoked after being dropped");
41 }
42 let ret = {
45 let f: &dyn Fn($($var),*) -> R = mem::transmute((a, b));
46 $(
47 let $var = <$var as FromWasmAbi>::from_abi($var::Abi::join($arg1, $arg2, $arg3, $arg4));
48 )*
49 f($($var),*)
50 };
51 ret.return_abi().into()
52 }
53
54 #[allow(coherence_leak_check)]
55 impl<$($var,)* R> WasmDescribe for dyn Fn($($var),*) -> R + '_
56 where $($var: FromWasmAbi,)*
57 R: ReturnWasmAbi
58 {
59 #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
60 fn describe() {
61 inform(FUNCTION);
62 inform($invoke::<$($var,)* R> as usize as u32);
63 inform($cnt);
64 $(<$var as WasmDescribe>::describe();)*
65 <R as WasmDescribe>::describe();
66 <R as WasmDescribe>::describe();
67 }
68 }
69
70 #[allow(coherence_leak_check)]
71 impl<$($var,)* R> IntoWasmAbi for &'_ mut (dyn FnMut($($var),*) -> R + '_)
72 where $($var: FromWasmAbi,)*
73 R: ReturnWasmAbi
74 {
75 type Abi = WasmSlice;
76
77 fn into_abi(self) -> WasmSlice {
78 unsafe {
79 let (a, b): (usize, usize) = mem::transmute(self);
80 WasmSlice { ptr: a as u32, len: b as u32 }
81 }
82 }
83 }
84
85 #[allow(non_snake_case)]
86 unsafe extern "C" fn $invoke_mut<$($var: FromWasmAbi,)* R: ReturnWasmAbi>(
87 a: usize,
88 b: usize,
89 $(
90 $arg1: <$var::Abi as WasmAbi>::Prim1,
91 $arg2: <$var::Abi as WasmAbi>::Prim2,
92 $arg3: <$var::Abi as WasmAbi>::Prim3,
93 $arg4: <$var::Abi as WasmAbi>::Prim4,
94 )*
95 ) -> WasmRet<R::Abi> {
96 if a == 0 {
97 throw_str("closure invoked recursively or after being dropped");
98 }
99 let ret = {
102 let f: &mut dyn FnMut($($var),*) -> R = mem::transmute((a, b));
103 $(
104 let $var = <$var as FromWasmAbi>::from_abi($var::Abi::join($arg1, $arg2, $arg3, $arg4));
105 )*
106 f($($var),*)
107 };
108 ret.return_abi().into()
109 }
110
111 #[allow(coherence_leak_check)]
112 impl<$($var,)* R> WasmDescribe for dyn FnMut($($var),*) -> R + '_
113 where $($var: FromWasmAbi,)*
114 R: ReturnWasmAbi
115 {
116 #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
117 fn describe() {
118 inform(FUNCTION);
119 inform($invoke_mut::<$($var,)* R> as usize as u32);
120 inform($cnt);
121 $(<$var as WasmDescribe>::describe();)*
122 <R as WasmDescribe>::describe();
123 <R as WasmDescribe>::describe();
124 }
125 }
126 )*)
127}
128
129stack_closures! {
130 (0 invoke0 invoke0_mut)
131 (1 invoke1 invoke1_mut A a1 a2 a3 a4)
132 (2 invoke2 invoke2_mut A a1 a2 a3 a4 B b1 b2 b3 b4)
133 (3 invoke3 invoke3_mut A a1 a2 a3 a4 B b1 b2 b3 b4 C c1 c2 c3 c4)
134 (4 invoke4 invoke4_mut A a1 a2 a3 a4 B b1 b2 b3 b4 C c1 c2 c3 c4 D d1 d2 d3 d4)
135 (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)
136 (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)
137 (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)
138 (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)
139}
140
141impl<A, R> IntoWasmAbi for &(dyn Fn(&A) -> R + '_)
142where
143 A: RefFromWasmAbi,
144 R: ReturnWasmAbi,
145{
146 type Abi = WasmSlice;
147
148 fn into_abi(self) -> WasmSlice {
149 unsafe {
150 let (a, b): (usize, usize) = mem::transmute(self);
151 WasmSlice {
152 ptr: a as u32,
153 len: b as u32,
154 }
155 }
156 }
157}
158
159#[allow(non_snake_case)]
160#[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
161unsafe extern "C" fn invoke1_ref<A: RefFromWasmAbi, R: ReturnWasmAbi>(
162 a: usize,
163 b: usize,
164 arg1: <A::Abi as WasmAbi>::Prim1,
165 arg2: <A::Abi as WasmAbi>::Prim2,
166 arg3: <A::Abi as WasmAbi>::Prim3,
167 arg4: <A::Abi as WasmAbi>::Prim4,
168) -> WasmRet<R::Abi> {
169 if a == 0 {
170 throw_str("closure invoked after being dropped");
171 }
172 let ret = {
175 let f: &dyn Fn(&A) -> R = mem::transmute((a, b));
176 let arg = <A as RefFromWasmAbi>::ref_from_abi(A::Abi::join(arg1, arg2, arg3, arg4));
177 f(&*arg)
178 };
179 ret.return_abi().into()
180}
181
182impl<A, R> WasmDescribe for dyn Fn(&A) -> R + '_
183where
184 A: RefFromWasmAbi,
185 R: ReturnWasmAbi,
186{
187 #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
188 fn describe() {
189 inform(FUNCTION);
190 inform(invoke1_ref::<A, R> as usize as u32);
191 inform(1);
192 <&A as WasmDescribe>::describe();
193 <R as WasmDescribe>::describe();
194 <R as WasmDescribe>::describe();
195 }
196}
197
198impl<A, R> IntoWasmAbi for &mut (dyn FnMut(&A) -> R + '_)
199where
200 A: RefFromWasmAbi,
201 R: ReturnWasmAbi,
202{
203 type Abi = WasmSlice;
204
205 fn into_abi(self) -> WasmSlice {
206 unsafe {
207 let (a, b): (usize, usize) = mem::transmute(self);
208 WasmSlice {
209 ptr: a as u32,
210 len: b as u32,
211 }
212 }
213 }
214}
215
216#[allow(non_snake_case)]
217#[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
218unsafe extern "C" fn invoke1_mut_ref<A: RefFromWasmAbi, R: ReturnWasmAbi>(
219 a: usize,
220 b: usize,
221 arg1: <A::Abi as WasmAbi>::Prim1,
222 arg2: <A::Abi as WasmAbi>::Prim2,
223 arg3: <A::Abi as WasmAbi>::Prim3,
224 arg4: <A::Abi as WasmAbi>::Prim4,
225) -> WasmRet<R::Abi> {
226 if a == 0 {
227 throw_str("closure invoked recursively or after being dropped");
228 }
229 let ret = {
232 let f: &mut dyn FnMut(&A) -> R = mem::transmute((a, b));
233 let arg = <A as RefFromWasmAbi>::ref_from_abi(A::Abi::join(arg1, arg2, arg3, arg4));
234 f(&*arg)
235 };
236 ret.return_abi().into()
237}
238
239impl<A, R> WasmDescribe for dyn FnMut(&A) -> R + '_
240where
241 A: RefFromWasmAbi,
242 R: ReturnWasmAbi,
243{
244 #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
245 fn describe() {
246 inform(FUNCTION);
247 inform(invoke1_mut_ref::<A, R> as usize as u32);
248 inform(1);
249 <&A as WasmDescribe>::describe();
250 <R as WasmDescribe>::describe();
251 <R as WasmDescribe>::describe();
252 }
253}