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