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;
20
21#[inline]
22fn release<T>(_: T) {}
23
24macro_rules! closures {
25 ([$($maybe_unwind_safe:tt)*] $($rest:tt)*) => {
27 closures!(@process [$($maybe_unwind_safe)*] $($rest)*);
28 };
29
30 (@process [$($unwind_safe:tt)*] ($($var:ident $arg1:ident $arg2:ident $arg3:ident $arg4:ident)*) $($rest:tt)*) => {
32 closures!(@impl_for_args ($($var),*) FromWasmAbi [$($unwind_safe)*] $(try_from_abi($var) => $var $arg1 $arg2 $arg3 $arg4)*);
33 closures!(@process [$($unwind_safe)*] $($rest)*);
34 };
35
36 (@process [$($unwind_safe:tt)*]) => {};
38
39 (@count_one $ty:ty) => (1);
41
42 (@errs) => {};
44 (@errs $first:ident $($rest:ident)*) => {
45 closures!(@errs $($rest)*);
46 let $first = $first.err();
47 };
48
49 (@release) => {};
51 (@release $first:ident $($rest:ident)*) => {
52 closures!(@release $($rest)*);
53 release($first);
54 };
55
56 (@describe ( $($ty:ty),* )) => {
57 const ARG_COUNT: u32 = 0 $(+ closures!(@count_one $ty))*;
60 inform(ARG_COUNT);
61 $(<$ty>::describe();)*
62 };
63
64 (@closure ($($ty:ty),*) $($var:ident)* $body:block) => (move |$($var: $ty),*| $body);
68
69 (@impl_for_fn $is_mut:literal [$($mut:ident)?] $Fn:ident $FnArgs:tt $FromWasmAbi:ident $($try_fn:ident ($use_expr:expr) => $var:ident $arg1:ident $arg2:ident $arg3:ident $arg4:ident)*) => (const _: () = {
70 impl<$($var,)* R> IntoWasmAbi for &'_ $($mut)? (dyn $Fn $FnArgs -> R + '_)
71 where
72 Self: WasmDescribe,
73 {
74 type Abi = WasmSlice;
75
76 fn into_abi(self) -> WasmSlice {
77 unsafe {
78 let (a, b): (usize, usize) = mem::transmute(self);
79 WasmSlice::from_usize(a, b)
80 }
81 }
82 }
83
84 unsafe impl<'a, $($var,)* R> ErasableGeneric for &'a $($mut)? (dyn $Fn $FnArgs -> R + 'a)
85 where
86 $($var: ErasableGeneric,)*
87 R: ErasableGeneric
88 {
89 type Repr = &'a (dyn $Fn ($(<$var as ErasableGeneric>::Repr,)*) -> <R as ErasableGeneric>::Repr + 'a);
90 }
91
92 #[allow(non_snake_case)]
97 unsafe extern "C-unwind" fn invoke<$($var: $FromWasmAbi,)* R: ReturnWasmAbi, const UNWIND_SAFE: bool>(
98 a: WasmWord,
99 b: WasmWord,
100 $(
101 $arg1: <$var::Abi as WasmAbi>::Prim1,
102 $arg2: <$var::Abi as WasmAbi>::Prim2,
103 $arg3: <$var::Abi as WasmAbi>::Prim3,
104 $arg4: <$var::Abi as WasmAbi>::Prim4,
105 )*
106 ) -> WasmRet<R::Abi> {
107 $(
110 let $var = $var::$try_fn($var::Abi::join($arg1, $arg2, $arg3, $arg4));
111 )*
112 let ($($var,)*) = match ($($var,)*) {
113 ($(Ok($var),)*) if !a.is_zero() => ($($var,)*),
114 ($($var,)*) => {
115 closures!(@errs $($var)*);
116 throw_str(if a.is_zero() {
117 "closure invoked recursively or after being dropped"
118 } else {
119 None $(.or($var))*.unwrap_or_default()
120 })
121 }
122 };
123 let ret = {
124 let f: & $($mut)? dyn $Fn $FnArgs -> R =
125 mem::transmute((a.into_usize(), b.into_usize()));
126 if UNWIND_SAFE {
127 maybe_catch_unwind(AssertUnwindSafe(|| f($($use_expr),*)))
128 } else {
129 f($($use_expr),*)
130 }
131 };
132 ret.return_abi().into()
133 }
134
135 #[allow(clippy::fn_to_numeric_cast)]
136 impl<$($var,)* R> WasmDescribe for dyn $Fn $FnArgs -> R + '_
137 where
138 $($var: $FromWasmAbi,)*
139 R: ReturnWasmAbi,
140 {
141 #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
142 fn describe() {
143 <Self as WasmClosure>::describe_invoke::<true>();
146 }
147 }
148
149 unsafe impl<'__closure, $($var,)* R> WasmClosure for dyn $Fn $FnArgs -> R + '__closure
150 where
151 $($var: $FromWasmAbi,)*
152 R: ReturnWasmAbi,
153 {
154 const IS_MUT: bool = $is_mut;
155 type Static = dyn $Fn $FnArgs -> R;
156 type AsMut = dyn FnMut $FnArgs -> R + '__closure;
157 #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
158 fn describe_invoke<const UNWIND_SAFE: bool>() {
159 inform(FUNCTION);
160 inform(invoke::<$($var,)* R, UNWIND_SAFE> as *const () as usize as u32);
161 closures!(@describe $FnArgs);
162 R::describe();
163 R::describe();
164 }
165 }
166
167 impl<T, $($var,)* R> IntoWasmClosure<dyn $Fn $FnArgs -> R> for T
168 where
169 T: 'static + $Fn $FnArgs -> R,
170 {
171 fn unsize(self: Box<Self>) -> Box<dyn $Fn $FnArgs -> R> { self }
172 }
173 };);
174
175 (@impl_unsize_closure_ref $FnArgs:tt $FromWasmAbi:ident $($try_fn:ident ($use_expr:expr) => $var:ident $arg1:ident $arg2:ident $arg3:ident $arg4:ident)*) => (
179 impl<'a, T: 'a, $($var: 'a + $FromWasmAbi,)* R: 'a + ReturnWasmAbi> IntoWasmClosureRef<dyn Fn $FnArgs -> R + 'a> for T
180 where
181 T: Fn $FnArgs -> R,
182 {
183 fn unsize_closure_ref(&self) -> &(dyn Fn $FnArgs -> R + 'a) { self }
184 }
185
186 impl<'a, T: 'a, $($var: 'a + $FromWasmAbi,)* R: 'a + ReturnWasmAbi> IntoWasmClosureRefMut<dyn FnMut $FnArgs -> R + 'a> for T
187 where
188 T: FnMut $FnArgs -> R,
189 {
190 fn unsize_closure_ref(&mut self) -> &mut (dyn FnMut $FnArgs -> R + 'a) { self }
191 }
192 );
193
194 (@impl_for_args $FnArgs:tt $FromWasmAbi:ident [$($maybe_unwind_safe:tt)*] $($try_fn:ident ($use_expr:expr) => $var:ident $arg1:ident $arg2:ident $arg3:ident $arg4:ident)*) => {
195 closures!(@impl_for_fn false [] Fn $FnArgs $FromWasmAbi $($try_fn ($use_expr) => $var $arg1 $arg2 $arg3 $arg4)*);
196 closures!(@impl_for_fn true [mut] FnMut $FnArgs $FromWasmAbi $($try_fn ($use_expr) => $var $arg1 $arg2 $arg3 $arg4)*);
197 closures!(@impl_unsize_closure_ref $FnArgs $FromWasmAbi $($try_fn ($use_expr) => $var $arg1 $arg2 $arg3 $arg4)*);
198
199 #[allow(non_snake_case, unused_parens)]
214 impl<T, $($var,)* R> WasmClosureFnOnce<dyn FnMut $FnArgs -> R, $FnArgs, R> for T
215 where
216 T: 'static + (FnOnce $FnArgs -> R),
217 $($var: $FromWasmAbi + 'static,)*
218 R: ReturnWasmAbi + 'static,
219 $($maybe_unwind_safe)*
220 {
221 fn into_fn_mut(self) -> Box<dyn FnMut $FnArgs -> R> {
222 let mut me = Some(self);
223 Box::new(move |$($var),*| {
224 match me.take() {
225 Some(me) => me($($var),*),
226 None => {
227 closures!(@release $($var)*);
228 throw_str("FnOnce called more than once")
229 }
230 }
231 })
232 }
233
234 fn into_js_function(self) -> JsValue {
235 use alloc::rc::Rc;
236 use crate::__rt::WasmRefCell;
237
238 let rc1 = Rc::new(WasmRefCell::new(None));
239 let rc2 = rc1.clone();
240
241 let closure = Closure::once(closures!(@closure $FnArgs $($var)* {
242 let result = self($($var),*);
243
244 debug_assert_eq!(Rc::strong_count(&rc2), 1);
247 let option_closure = rc2.borrow_mut().take();
248 debug_assert!(option_closure.is_some());
249 drop(option_closure);
250
251 result
252 }));
253
254 let js_val = closure.as_ref().clone();
255
256 *rc1.borrow_mut() = Some(closure);
257 debug_assert_eq!(Rc::strong_count(&rc1), 2);
258 drop(rc1);
259
260 js_val
261 }
262 }
263
264 #[allow(non_snake_case, unused_parens)]
265 impl<T, $($var,)* R> WasmClosureFnOnceAbort<dyn FnMut $FnArgs -> R, $FnArgs, R> for T
266 where
267 T: 'static + (FnOnce $FnArgs -> R),
268 $($var: $FromWasmAbi + 'static,)*
269 R: ReturnWasmAbi + 'static,
270 {
271 fn into_fn_mut(self) -> Box<dyn FnMut $FnArgs -> R> {
272 let mut me = Some(self);
273 Box::new(move |$($var),*| {
274 match me.take() {
275 Some(me) => me($($var),*),
276 None => {
277 closures!(@release $($var)*);
278 throw_str("FnOnce called more than once")
279 }
280 }
281 })
282 }
283
284 fn into_js_function(self) -> JsValue {
285 use alloc::rc::Rc;
286 use crate::__rt::WasmRefCell;
287
288 let rc1 = Rc::new(WasmRefCell::new(None));
289 let rc2 = rc1.clone();
290
291 let closure = Closure::once_aborting(closures!(@closure $FnArgs $($var)* {
293 let result = self($($var),*);
294
295 debug_assert_eq!(Rc::strong_count(&rc2), 1);
298 let option_closure = rc2.borrow_mut().take();
299 debug_assert!(option_closure.is_some());
300 drop(option_closure);
301
302 result
303 }));
304
305 let js_val = closure.as_ref().clone();
306
307 *rc1.borrow_mut() = Some(closure);
308 debug_assert_eq!(Rc::strong_count(&rc1), 2);
309 drop(rc1);
310
311 js_val
312 }
313 }
314 };
315
316 ([$($unwind_safe:tt)*] $( ($($var:ident $arg1:ident $arg2:ident $arg3:ident $arg4:ident)*) )*) => ($(
317 closures!(@impl_for_args ($($var),*) FromWasmAbi [$($maybe_unwind_safe)*] $(try_from_abi($var) => $var $arg1 $arg2 $arg3 $arg4)*);
318 )*);
319}
320
321#[cfg(all(feature = "std", target_arch = "wasm32", panic = "unwind"))]
322closures! {
323 [T: core::panic::UnwindSafe,]
324 ()
325 (A a1 a2 a3 a4)
326 (A a1 a2 a3 a4 B b1 b2 b3 b4)
327 (A a1 a2 a3 a4 B b1 b2 b3 b4 C c1 c2 c3 c4)
328 (A a1 a2 a3 a4 B b1 b2 b3 b4 C c1 c2 c3 c4 D d1 d2 d3 d4)
329 (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)
330 (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)
331 (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)
332 (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)
333}
334
335#[cfg(not(all(feature = "std", target_arch = "wasm32", panic = "unwind")))]
336closures! {
337 []
338 ()
339 (A a1 a2 a3 a4)
340 (A a1 a2 a3 a4 B b1 b2 b3 b4)
341 (A a1 a2 a3 a4 B b1 b2 b3 b4 C c1 c2 c3 c4)
342 (A a1 a2 a3 a4 B b1 b2 b3 b4 C c1 c2 c3 c4 D d1 d2 d3 d4)
343 (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)
344 (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)
345 (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)
346 (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)
347}
348
349macro_rules! impl_fn_upcasts {
351 () => {
352 impl_fn_upcasts!(@arities
353 [0 []]
354 [1 [A1 B1] O1]
355 [2 [A1 B1 A2 B2] O2]
356 [3 [A1 B1 A2 B2 A3 B3] O3]
357 [4 [A1 B1 A2 B2 A3 B3 A4 B4] O4]
358 [5 [A1 B1 A2 B2 A3 B3 A4 B4 A5 B5] O5]
359 [6 [A1 B1 A2 B2 A3 B3 A4 B4 A5 B5 A6 B6] O6]
360 [7 [A1 B1 A2 B2 A3 B3 A4 B4 A5 B5 A6 B6 A7 B7] O7]
361 [8 [A1 B1 A2 B2 A3 B3 A4 B4 A5 B5 A6 B6 A7 B7 A8 B8] O8]
362 );
363 };
364
365 (@arities) => {};
366
367 (@arities [$n:tt $args:tt $($opt:ident)?] $([$rest_n:tt $rest_args:tt $($rest_opt:ident)?])*) => {
368 impl_fn_upcasts!(@same $args);
369 impl_fn_upcasts!(@cross_all $args [] $([$rest_n $rest_args $($rest_opt)?])*);
370 impl_fn_upcasts!(@arities $([$rest_n $rest_args $($rest_opt)?])*);
371 };
372
373 (@same []) => {
374 impl<R1, R2> UpcastFrom<fn() -> R1> for fn() -> R2
375 where
376 R2: UpcastFrom<R1>
377 {}
378
379 impl<'a, R1, R2> UpcastFrom<dyn Fn() -> R1 + 'a> for dyn Fn() -> R2 + 'a
380 where
381 R2: UpcastFrom<R1>
382 {}
383
384 impl<'a, R1, R2> UpcastFrom<dyn FnMut() -> R1 + 'a> for dyn FnMut() -> R2 + 'a
385 where
386 R2: UpcastFrom<R1>
387 {}
388 };
389
390 (@same [$($A1:ident $A2:ident)+]) => {
392 impl<R1, R2, $($A1, $A2),+> UpcastFrom<fn($($A1),+) -> R1> for fn($($A2),+) -> R2
393 where
394 R2: UpcastFrom<R1>,
395 $($A1: UpcastFrom<$A2>,)+
396 {}
397
398 impl<'a, R1, R2, $($A1, $A2),+> UpcastFrom<dyn Fn($($A1),+) -> R1 + 'a> for dyn Fn($($A2),+) -> R2 + 'a
399 where
400 R2: UpcastFrom<R1>,
401 $($A1: UpcastFrom<$A2>,)+
402 {}
403
404 impl<'a, R1, R2, $($A1, $A2),+> UpcastFrom<dyn FnMut($($A1),+) -> R1 + 'a> for dyn FnMut($($A2),+) -> R2 + 'a
405 where
406 R2: UpcastFrom<R1>,
407 $($A1: UpcastFrom<$A2>,)+
408 {}
409 };
410
411 (@cross_all $args:tt $opts:tt) => {};
413
414 (@cross_all $args:tt [$($opts:ident)*] [$next_n:tt $next_args:tt $next_opt:ident] $([$rest_n:tt $rest_args:tt $($rest_opt:ident)?])*) => {
416 impl_fn_upcasts!(@extend $args [$($opts)* $next_opt]);
417 impl_fn_upcasts!(@shrink $args [$($opts)* $next_opt]);
418 impl_fn_upcasts!(@cross_all $args [$($opts)* $next_opt] $([$rest_n $rest_args $($rest_opt)?])*);
419 };
420
421 (@extend [] [$($O:ident)+]) => {
423 impl<R1, R2, $($O),+> UpcastFrom<fn() -> R1> for fn($($O),+) -> R2
424 where
425 R2: UpcastFrom<R1>,
426 $($O: UpcastFrom<Undefined>,)+
427 {}
428
429 impl<'a, R1, R2, $($O),+> UpcastFrom<dyn Fn() -> R1 + 'a> for dyn Fn($($O),+) -> R2 + 'a
430 where
431 R2: UpcastFrom<R1>,
432 $($O: UpcastFrom<Undefined>,)+
433 {}
434
435 impl<'a, R1, R2, $($O),+> UpcastFrom<dyn FnMut() -> R1 + 'a> for dyn FnMut($($O),+) -> R2 + 'a
436 where
437 R2: UpcastFrom<R1>,
438 $($O: UpcastFrom<Undefined>,)+
439 {}
440 };
441
442 (@extend [$($A1:ident $A2:ident)+] [$($O:ident)+]) => {
444 impl<R1, R2, $($A1, $A2,)+ $($O),+> UpcastFrom<fn($($A1),+) -> R1> for fn($($A2,)+ $($O),+) -> R2
445 where
446 R2: UpcastFrom<R1>,
447 $($A1: UpcastFrom<$A2>,)+ $($O: UpcastFrom<Undefined>,)+
449 {}
450
451 impl<'a, R1, R2, $($A1, $A2,)+ $($O),+> UpcastFrom<dyn Fn($($A1),+) -> R1 + 'a> for dyn Fn($($A2,)+ $($O),+) -> R2 + 'a
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 FnMut($($A1),+) -> R1 + 'a> for dyn FnMut($($A2,)+ $($O),+) -> R2 + 'a
459 where
460 R2: UpcastFrom<R1>,
461 $($A1: UpcastFrom<$A2>,)+ $($O: UpcastFrom<Undefined>,)+
463 {}
464 };
465
466 (@shrink [] [$($O:ident)+]) => {
468 impl<R1, R2, $($O),+> UpcastFrom<fn($($O),+) -> R1> for fn() -> R2
469 where
470 R2: UpcastFrom<R1>,
471 $($O: UpcastFrom<Undefined>,)+
472 {}
473
474 impl<'a, R1, R2, $($O),+> UpcastFrom<dyn Fn($($O),+) -> R1 + 'a> for dyn Fn() -> R2 + 'a
475 where
476 R2: UpcastFrom<R1>,
477 $($O: UpcastFrom<Undefined>,)+
478 {}
479
480 impl<'a, R1, R2, $($O),+> UpcastFrom<dyn FnMut($($O),+) -> R1 + 'a> for dyn FnMut() -> R2 + 'a
481 where
482 R2: UpcastFrom<R1>,
483 $($O: UpcastFrom<Undefined>,)+
484 {}
485 };
486
487 (@shrink [$($A1:ident $A2:ident)+] [$($O:ident)+]) => {
489 impl<R1, R2, $($A1, $A2,)+ $($O),+> UpcastFrom<fn($($A1,)+ $($O),+) -> R1> for fn($($A2),+) -> R2
490 where
491 R2: UpcastFrom<R1>,
492 $($A1: UpcastFrom<$A2>,)+ $($O: UpcastFrom<Undefined>,)+
494 {}
495
496 impl<'a, R1, R2, $($A1, $A2,)+ $($O),+> UpcastFrom<dyn Fn($($A1,)+ $($O),+) -> R1 + 'a> for dyn Fn($($A2),+) -> R2 + 'a
497 where
498 R2: UpcastFrom<R1>,
499 $($A1: UpcastFrom<$A2>,)+ $($O: UpcastFrom<Undefined>,)+
501 {}
502
503 impl<'a, R1, R2, $($A1, $A2,)+ $($O),+> UpcastFrom<dyn FnMut($($A1,)+ $($O),+) -> R1 + 'a> for dyn FnMut($($A2),+) -> R2 + 'a
504 where
505 R2: UpcastFrom<R1>,
506 $($A1: UpcastFrom<$A2>,)+ $($O: UpcastFrom<Undefined>,)+
508 {}
509 };
510}
511
512impl_fn_upcasts!();
513
514#[allow(coherence_leak_check)]
522const _: () = {
523 #[cfg(all(feature = "std", target_arch = "wasm32", panic = "unwind"))]
524 closures!(@impl_for_args (&A) RefFromWasmAbi [T: core::panic::UnwindSafe,] try_ref_from_abi(&*A) => A a1 a2 a3 a4);
525
526 #[cfg(not(all(feature = "std", target_arch = "wasm32", panic = "unwind")))]
527 closures!(@impl_for_args (&A) RefFromWasmAbi [] try_ref_from_abi(&*A) => A a1 a2 a3 a4);
528};
529
530impl<'a: 'b, 'b, T1, T2> UpcastFrom<ScopedClosure<'a, T1>> for ScopedClosure<'b, T2>
539where
540 T1: ?Sized + WasmClosure,
541 T2: ?Sized + WasmClosure + UpcastFrom<T1>,
542{
543}