1use alloc::boxed::Box;
2use core::mem;
3use core::panic::AssertUnwindSafe;
4
5use crate::__rt::marker::ErasableGeneric;
6use crate::__rt::maybe_catch_unwind;
7use crate::__rt::WasmWord;
8use crate::closure::{
9 Closure, IntoWasmClosure, IntoWasmClosureRef, IntoWasmClosureRefMut, ScopedClosure,
10 WasmClosure, WasmClosureFnOnce, WasmClosureFnOnceAbort,
11};
12use crate::convert::slices::WasmSlice;
13use crate::convert::traits::UpcastFrom;
14use crate::convert::RefFromWasmAbi;
15use crate::convert::{FromWasmAbi, IntoWasmAbi, ReturnWasmAbi, WasmAbi, WasmRet};
16use crate::describe::{inform, WasmDescribe, FUNCTION};
17use crate::sys::Undefined;
18use crate::throw_str;
19use crate::JsValue;
20use crate::UnwrapThrowExt;
21
22macro_rules! closures {
23 ([$($maybe_unwind_safe:tt)*] $($rest:tt)*) => {
25 closures!(@process [$($maybe_unwind_safe)*] $($rest)*);
26 };
27
28 (@process [$($unwind_safe:tt)*] ($($var:ident $arg1:ident $arg2:ident $arg3:ident $arg4:ident)*) $($rest:tt)*) => {
30 closures!(@impl_for_args ($($var),*) FromWasmAbi [$($unwind_safe)*] $($var::from_abi($var) => $var $arg1 $arg2 $arg3 $arg4)*);
31 closures!(@process [$($unwind_safe)*] $($rest)*);
32 };
33
34 (@process [$($unwind_safe:tt)*]) => {};
36
37 (@count_one $ty:ty) => (1);
39
40 (@describe ( $($ty:ty),* )) => {
41 const ARG_COUNT: u32 = 0 $(+ closures!(@count_one $ty))*;
44 inform(ARG_COUNT);
45 $(<$ty>::describe();)*
46 };
47
48 (@closure ($($ty:ty),*) $($var:ident)* $body:block) => (move |$($var: $ty),*| $body);
52
53 (@impl_for_fn $is_mut:literal [$($mut:ident)?] $Fn:ident $FnArgs:tt $FromWasmAbi:ident $($var_expr:expr => $var:ident $arg1:ident $arg2:ident $arg3:ident $arg4:ident)*) => (const _: () = {
54 impl<$($var,)* R> IntoWasmAbi for &'_ $($mut)? (dyn $Fn $FnArgs -> R + '_)
55 where
56 Self: WasmDescribe,
57 {
58 type Abi = WasmSlice;
59
60 fn into_abi(self) -> WasmSlice {
61 unsafe {
62 let (a, b): (usize, usize) = mem::transmute(self);
63 WasmSlice::from_usize(a, b)
64 }
65 }
66 }
67
68 unsafe impl<'a, $($var,)* R> ErasableGeneric for &'a $($mut)? (dyn $Fn $FnArgs -> R + 'a)
69 where
70 $($var: ErasableGeneric,)*
71 R: ErasableGeneric
72 {
73 type Repr = &'static (dyn $Fn ($(<$var as ErasableGeneric>::Repr,)*) -> <R as ErasableGeneric>::Repr + 'static);
74 }
75
76 #[allow(non_snake_case)]
81 unsafe extern "C-unwind" fn invoke<$($var: $FromWasmAbi,)* R: ReturnWasmAbi, const UNWIND_SAFE: bool>(
82 a: WasmWord,
83 b: WasmWord,
84 $(
85 $arg1: <$var::Abi as WasmAbi>::Prim1,
86 $arg2: <$var::Abi as WasmAbi>::Prim2,
87 $arg3: <$var::Abi as WasmAbi>::Prim3,
88 $arg4: <$var::Abi as WasmAbi>::Prim4,
89 )*
90 ) -> WasmRet<R::Abi> {
91 if a.is_zero() {
92 throw_str("closure invoked recursively or after being dropped");
93 }
94 let ret = {
95 let f: & $($mut)? dyn $Fn $FnArgs -> R =
96 mem::transmute((a.into_usize(), b.into_usize()));
97 $(
98 let $var = $var::Abi::join($arg1, $arg2, $arg3, $arg4);
99 )*
100 if UNWIND_SAFE {
101 maybe_catch_unwind(AssertUnwindSafe(|| f($($var_expr),*)))
102 } else {
103 f($($var_expr),*)
104 }
105 };
106 ret.return_abi().into()
107 }
108
109 #[allow(clippy::fn_to_numeric_cast)]
110 impl<$($var,)* R> WasmDescribe for dyn $Fn $FnArgs -> R + '_
111 where
112 $($var: $FromWasmAbi,)*
113 R: ReturnWasmAbi,
114 {
115 #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
116 fn describe() {
117 <Self as WasmClosure>::describe_invoke::<true>();
120 }
121 }
122
123 unsafe impl<'__closure, $($var,)* R> WasmClosure for dyn $Fn $FnArgs -> R + '__closure
124 where
125 $($var: $FromWasmAbi,)*
126 R: ReturnWasmAbi,
127 {
128 const IS_MUT: bool = $is_mut;
129 type Static = dyn $Fn $FnArgs -> R;
130 type AsMut = dyn FnMut $FnArgs -> R + '__closure;
131 #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
132 fn describe_invoke<const UNWIND_SAFE: bool>() {
133 inform(FUNCTION);
134 inform(invoke::<$($var,)* R, UNWIND_SAFE> as *const () as usize as u32);
135 closures!(@describe $FnArgs);
136 R::describe();
137 R::describe();
138 }
139 }
140
141 impl<T, $($var,)* R> IntoWasmClosure<dyn $Fn $FnArgs -> R> for T
142 where
143 T: 'static + $Fn $FnArgs -> R,
144 {
145 fn unsize(self: Box<Self>) -> Box<dyn $Fn $FnArgs -> R> { self }
146 }
147 };);
148
149 (@impl_unsize_closure_ref $FnArgs:tt $FromWasmAbi:ident $($var_expr:expr => $var:ident $arg1:ident $arg2:ident $arg3:ident $arg4:ident)*) => (
153 impl<'a, T: 'a, $($var: 'a + $FromWasmAbi,)* R: 'a + ReturnWasmAbi> IntoWasmClosureRef<dyn Fn $FnArgs -> R + 'a> for T
154 where
155 T: Fn $FnArgs -> R,
156 {
157 fn unsize_closure_ref(&self) -> &(dyn Fn $FnArgs -> R + 'a) { self }
158 }
159
160 impl<'a, T: 'a, $($var: 'a + $FromWasmAbi,)* R: 'a + ReturnWasmAbi> IntoWasmClosureRefMut<dyn FnMut $FnArgs -> R + 'a> for T
161 where
162 T: FnMut $FnArgs -> R,
163 {
164 fn unsize_closure_ref(&mut self) -> &mut (dyn FnMut $FnArgs -> R + 'a) { self }
165 }
166 );
167
168 (@impl_for_args $FnArgs:tt $FromWasmAbi:ident [$($maybe_unwind_safe:tt)*] $($var_expr:expr => $var:ident $arg1:ident $arg2:ident $arg3:ident $arg4:ident)*) => {
169 closures!(@impl_for_fn false [] Fn $FnArgs $FromWasmAbi $($var_expr => $var $arg1 $arg2 $arg3 $arg4)*);
170 closures!(@impl_for_fn true [mut] FnMut $FnArgs $FromWasmAbi $($var_expr => $var $arg1 $arg2 $arg3 $arg4)*);
171 closures!(@impl_unsize_closure_ref $FnArgs $FromWasmAbi $($var_expr => $var $arg1 $arg2 $arg3 $arg4)*);
172
173 #[allow(non_snake_case, unused_parens)]
188 impl<T, $($var,)* R> WasmClosureFnOnce<dyn FnMut $FnArgs -> R, $FnArgs, R> for T
189 where
190 T: 'static + (FnOnce $FnArgs -> R),
191 $($var: $FromWasmAbi + 'static,)*
192 R: ReturnWasmAbi + 'static,
193 $($maybe_unwind_safe)*
194 {
195 fn into_fn_mut(self) -> Box<dyn FnMut $FnArgs -> R> {
196 let mut me = Some(self);
197 Box::new(move |$($var),*| {
198 let me = me.take().expect_throw("FnOnce called more than once");
199 me($($var),*)
200 })
201 }
202
203 fn into_js_function(self) -> JsValue {
204 use alloc::rc::Rc;
205 use crate::__rt::WasmRefCell;
206
207 let rc1 = Rc::new(WasmRefCell::new(None));
208 let rc2 = rc1.clone();
209
210 let closure = Closure::once(closures!(@closure $FnArgs $($var)* {
211 let result = self($($var),*);
212
213 debug_assert_eq!(Rc::strong_count(&rc2), 1);
216 let option_closure = rc2.borrow_mut().take();
217 debug_assert!(option_closure.is_some());
218 drop(option_closure);
219
220 result
221 }));
222
223 let js_val = closure.as_ref().clone();
224
225 *rc1.borrow_mut() = Some(closure);
226 debug_assert_eq!(Rc::strong_count(&rc1), 2);
227 drop(rc1);
228
229 js_val
230 }
231 }
232
233 #[allow(non_snake_case, unused_parens)]
234 impl<T, $($var,)* R> WasmClosureFnOnceAbort<dyn FnMut $FnArgs -> R, $FnArgs, R> for T
235 where
236 T: 'static + (FnOnce $FnArgs -> R),
237 $($var: $FromWasmAbi + 'static,)*
238 R: ReturnWasmAbi + 'static,
239 {
240 fn into_fn_mut(self) -> Box<dyn FnMut $FnArgs -> R> {
241 let mut me = Some(self);
242 Box::new(move |$($var),*| {
243 let me = me.take().expect_throw("FnOnce called more than once");
244 me($($var),*)
245 })
246 }
247
248 fn into_js_function(self) -> JsValue {
249 use alloc::rc::Rc;
250 use crate::__rt::WasmRefCell;
251
252 let rc1 = Rc::new(WasmRefCell::new(None));
253 let rc2 = rc1.clone();
254
255 let closure = Closure::once_aborting(closures!(@closure $FnArgs $($var)* {
257 let result = self($($var),*);
258
259 debug_assert_eq!(Rc::strong_count(&rc2), 1);
262 let option_closure = rc2.borrow_mut().take();
263 debug_assert!(option_closure.is_some());
264 drop(option_closure);
265
266 result
267 }));
268
269 let js_val = closure.as_ref().clone();
270
271 *rc1.borrow_mut() = Some(closure);
272 debug_assert_eq!(Rc::strong_count(&rc1), 2);
273 drop(rc1);
274
275 js_val
276 }
277 }
278 };
279
280 ([$($unwind_safe:tt)*] $( ($($var:ident $arg1:ident $arg2:ident $arg3:ident $arg4:ident)*) )*) => ($(
281 closures!(@impl_for_args ($($var),*) FromWasmAbi [$($maybe_unwind_safe)*] $($var::from_abi($var) => $var $arg1 $arg2 $arg3 $arg4)*);
282 )*);
283}
284
285#[cfg(all(feature = "std", target_arch = "wasm32", panic = "unwind"))]
286closures! {
287 [T: core::panic::UnwindSafe,]
288 ()
289 (A a1 a2 a3 a4)
290 (A a1 a2 a3 a4 B b1 b2 b3 b4)
291 (A a1 a2 a3 a4 B b1 b2 b3 b4 C c1 c2 c3 c4)
292 (A a1 a2 a3 a4 B b1 b2 b3 b4 C c1 c2 c3 c4 D d1 d2 d3 d4)
293 (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)
294 (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)
295 (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)
296 (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)
297}
298
299#[cfg(not(all(feature = "std", target_arch = "wasm32", panic = "unwind")))]
300closures! {
301 []
302 ()
303 (A a1 a2 a3 a4)
304 (A a1 a2 a3 a4 B b1 b2 b3 b4)
305 (A a1 a2 a3 a4 B b1 b2 b3 b4 C c1 c2 c3 c4)
306 (A a1 a2 a3 a4 B b1 b2 b3 b4 C c1 c2 c3 c4 D d1 d2 d3 d4)
307 (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)
308 (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)
309 (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)
310 (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)
311}
312
313macro_rules! impl_fn_upcasts {
315 () => {
316 impl_fn_upcasts!(@arities
317 [0 []]
318 [1 [A1 B1] O1]
319 [2 [A1 B1 A2 B2] O2]
320 [3 [A1 B1 A2 B2 A3 B3] O3]
321 [4 [A1 B1 A2 B2 A3 B3 A4 B4] O4]
322 [5 [A1 B1 A2 B2 A3 B3 A4 B4 A5 B5] O5]
323 [6 [A1 B1 A2 B2 A3 B3 A4 B4 A5 B5 A6 B6] O6]
324 [7 [A1 B1 A2 B2 A3 B3 A4 B4 A5 B5 A6 B6 A7 B7] O7]
325 [8 [A1 B1 A2 B2 A3 B3 A4 B4 A5 B5 A6 B6 A7 B7 A8 B8] O8]
326 );
327 };
328
329 (@arities) => {};
330
331 (@arities [$n:tt $args:tt $($opt:ident)?] $([$rest_n:tt $rest_args:tt $($rest_opt:ident)?])*) => {
332 impl_fn_upcasts!(@same $args);
333 impl_fn_upcasts!(@cross_all $args [] $([$rest_n $rest_args $($rest_opt)?])*);
334 impl_fn_upcasts!(@arities $([$rest_n $rest_args $($rest_opt)?])*);
335 };
336
337 (@same []) => {
338 impl<R1, R2> UpcastFrom<fn() -> R1> for fn() -> R2
339 where
340 R2: UpcastFrom<R1>
341 {}
342
343 impl<'a, R1, R2> UpcastFrom<dyn Fn() -> R1 + 'a> for dyn Fn() -> R2 + 'a
344 where
345 R2: UpcastFrom<R1>
346 {}
347
348 impl<'a, R1, R2> UpcastFrom<dyn FnMut() -> R1 + 'a> for dyn FnMut() -> R2 + 'a
349 where
350 R2: UpcastFrom<R1>
351 {}
352 };
353
354 (@same [$($A1:ident $A2:ident)+]) => {
356 impl<R1, R2, $($A1, $A2),+> UpcastFrom<fn($($A1),+) -> R1> for fn($($A2),+) -> R2
357 where
358 R2: UpcastFrom<R1>,
359 $($A1: UpcastFrom<$A2>,)+
360 {}
361
362 impl<'a, R1, R2, $($A1, $A2),+> UpcastFrom<dyn Fn($($A1),+) -> R1 + 'a> for dyn Fn($($A2),+) -> R2 + 'a
363 where
364 R2: UpcastFrom<R1>,
365 $($A1: UpcastFrom<$A2>,)+
366 {}
367
368 impl<'a, R1, R2, $($A1, $A2),+> UpcastFrom<dyn FnMut($($A1),+) -> R1 + 'a> for dyn FnMut($($A2),+) -> R2 + 'a
369 where
370 R2: UpcastFrom<R1>,
371 $($A1: UpcastFrom<$A2>,)+
372 {}
373 };
374
375 (@cross_all $args:tt $opts:tt) => {};
377
378 (@cross_all $args:tt [$($opts:ident)*] [$next_n:tt $next_args:tt $next_opt:ident] $([$rest_n:tt $rest_args:tt $($rest_opt:ident)?])*) => {
380 impl_fn_upcasts!(@extend $args [$($opts)* $next_opt]);
381 impl_fn_upcasts!(@shrink $args [$($opts)* $next_opt]);
382 impl_fn_upcasts!(@cross_all $args [$($opts)* $next_opt] $([$rest_n $rest_args $($rest_opt)?])*);
383 };
384
385 (@extend [] [$($O:ident)+]) => {
387 impl<R1, R2, $($O),+> UpcastFrom<fn() -> R1> for fn($($O),+) -> R2
388 where
389 R2: UpcastFrom<R1>,
390 $($O: UpcastFrom<Undefined>,)+
391 {}
392
393 impl<'a, R1, R2, $($O),+> UpcastFrom<dyn Fn() -> R1 + 'a> for dyn Fn($($O),+) -> R2 + 'a
394 where
395 R2: UpcastFrom<R1>,
396 $($O: UpcastFrom<Undefined>,)+
397 {}
398
399 impl<'a, R1, R2, $($O),+> UpcastFrom<dyn FnMut() -> R1 + 'a> for dyn FnMut($($O),+) -> R2 + 'a
400 where
401 R2: UpcastFrom<R1>,
402 $($O: UpcastFrom<Undefined>,)+
403 {}
404 };
405
406 (@extend [$($A1:ident $A2:ident)+] [$($O:ident)+]) => {
408 impl<R1, R2, $($A1, $A2,)+ $($O),+> UpcastFrom<fn($($A1),+) -> R1> for fn($($A2,)+ $($O),+) -> R2
409 where
410 R2: UpcastFrom<R1>,
411 $($A1: UpcastFrom<$A2>,)+ $($O: UpcastFrom<Undefined>,)+
413 {}
414
415 impl<'a, R1, R2, $($A1, $A2,)+ $($O),+> UpcastFrom<dyn Fn($($A1),+) -> R1 + 'a> for dyn Fn($($A2,)+ $($O),+) -> R2 + 'a
416 where
417 R2: UpcastFrom<R1>,
418 $($A1: UpcastFrom<$A2>,)+ $($O: UpcastFrom<Undefined>,)+
420 {}
421
422 impl<'a, R1, R2, $($A1, $A2,)+ $($O),+> UpcastFrom<dyn FnMut($($A1),+) -> R1 + 'a> for dyn FnMut($($A2,)+ $($O),+) -> R2 + 'a
423 where
424 R2: UpcastFrom<R1>,
425 $($A1: UpcastFrom<$A2>,)+ $($O: UpcastFrom<Undefined>,)+
427 {}
428 };
429
430 (@shrink [] [$($O:ident)+]) => {
432 impl<R1, R2, $($O),+> UpcastFrom<fn($($O),+) -> R1> for fn() -> R2
433 where
434 R2: UpcastFrom<R1>,
435 $($O: UpcastFrom<Undefined>,)+
436 {}
437
438 impl<'a, R1, R2, $($O),+> UpcastFrom<dyn Fn($($O),+) -> R1 + 'a> for dyn Fn() -> R2 + 'a
439 where
440 R2: UpcastFrom<R1>,
441 $($O: UpcastFrom<Undefined>,)+
442 {}
443
444 impl<'a, R1, R2, $($O),+> UpcastFrom<dyn FnMut($($O),+) -> R1 + 'a> for dyn FnMut() -> R2 + 'a
445 where
446 R2: UpcastFrom<R1>,
447 $($O: UpcastFrom<Undefined>,)+
448 {}
449 };
450
451 (@shrink [$($A1:ident $A2:ident)+] [$($O:ident)+]) => {
453 impl<R1, R2, $($A1, $A2,)+ $($O),+> UpcastFrom<fn($($A1,)+ $($O),+) -> R1> for fn($($A2),+) -> R2
454 where
455 R2: UpcastFrom<R1>,
456 $($A1: UpcastFrom<$A2>,)+ $($O: UpcastFrom<Undefined>,)+
458 {}
459
460 impl<'a, R1, R2, $($A1, $A2,)+ $($O),+> UpcastFrom<dyn Fn($($A1,)+ $($O),+) -> R1 + 'a> for dyn Fn($($A2),+) -> R2 + 'a
461 where
462 R2: UpcastFrom<R1>,
463 $($A1: UpcastFrom<$A2>,)+ $($O: UpcastFrom<Undefined>,)+
465 {}
466
467 impl<'a, R1, R2, $($A1, $A2,)+ $($O),+> UpcastFrom<dyn FnMut($($A1,)+ $($O),+) -> R1 + 'a> for dyn FnMut($($A2),+) -> R2 + 'a
468 where
469 R2: UpcastFrom<R1>,
470 $($A1: UpcastFrom<$A2>,)+ $($O: UpcastFrom<Undefined>,)+
472 {}
473 };
474}
475
476impl_fn_upcasts!();
477
478#[allow(coherence_leak_check)]
486const _: () = {
487 #[cfg(all(feature = "std", target_arch = "wasm32", panic = "unwind"))]
488 closures!(@impl_for_args (&A) RefFromWasmAbi [T: core::panic::UnwindSafe,] &*A::ref_from_abi(A) => A a1 a2 a3 a4);
489
490 #[cfg(not(all(feature = "std", target_arch = "wasm32", panic = "unwind")))]
491 closures!(@impl_for_args (&A) RefFromWasmAbi [] &*A::ref_from_abi(A) => A a1 a2 a3 a4);
492};
493
494impl<'a: 'b, 'b, T1, T2> UpcastFrom<ScopedClosure<'a, T1>> for ScopedClosure<'b, T2>
502where
503 T1: ?Sized + WasmClosure,
504 T2: ?Sized + WasmClosure + UpcastFrom<T1>,
505{
506}