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