1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
use wasm_bindgen::{convert::FromWasmAbi, prelude::Closure, JsValue};

use crate::*;

pub trait IntoClosure<Params, Results> {
    fn into_closure(self) -> (JsValue, DropHandler);
}

impl<R, F> IntoClosure<(), R> for F
where
    F: Fn(Caller<()>) -> R + 'static,
    R: IntoImportResults + 'static,
{
    fn into_closure(self) -> (JsValue, DropHandler) {
        let closure = Closure::<dyn Fn() -> R::Results + 'static>::new(move || {
            self(Caller::new()).into_import_results()
        });

        let js_val: JsValue = closure.as_ref().into();

        (js_val, DropHandler::new(closure))
    }
}

macro_rules! impl_into_closure_single {
    ($ty:ty) => {
        impl<R, F> IntoClosure<$ty, R> for F
        where
            F: Fn(Caller<()>, $ty) -> R + 'static,
            R: IntoImportResults + 'static,
        {
            fn into_closure(self) -> (JsValue, DropHandler) {
                let closure =
                    Closure::<dyn Fn($ty) -> R::Results + 'static>::new(move |arg: $ty| {
                        self(Caller::new(), arg).into_import_results()
                    });

                let js_val: JsValue = closure.as_ref().into();

                (js_val, DropHandler::new(closure))
            }
        }
    };
}

impl_into_closure_single!(i32);
impl_into_closure_single!(i64);
impl_into_closure_single!(u32);
impl_into_closure_single!(u64);
impl_into_closure_single!(f32);
impl_into_closure_single!(f64);

macro_rules! into_closure_many {
    ($(($param: ident, $name: ident)),*) => {
        impl<$($name, )* R, F> IntoClosure<($($name),*), R> for F
        where
            F: Fn(Caller<()> $(, $name)*) -> R + 'static,
            $($name: FromWasmAbi + 'static,)*
            R: IntoImportResults + 'static,
        {
            fn into_closure(self) -> (JsValue, DropHandler) {
                let closure =
                    Closure::<dyn Fn($($name),*) -> R::Results + 'static>::new(move |$($param: $name),*| {
                        self(Caller::new() $(, $param)*).into_import_results()
                    });

                let js_val: JsValue = closure.as_ref().into();

                (js_val, DropHandler::new(closure))
            }
        }
    };
}

#[rustfmt::skip]
into_closure_many!((p0, P0), (p1, P1));
#[rustfmt::skip]
into_closure_many!((p0, P0), (p1, P1), (p2, P2));
#[rustfmt::skip]
into_closure_many!((p0, P0), (p1, P1), (p2, P2), (p3, P3));
#[rustfmt::skip]
into_closure_many!((p0, P0), (p1, P1), (p2, P2), (p3, P3), (p4, P4));
#[rustfmt::skip]
into_closure_many!((p0, P0), (p1, P1), (p2, P2), (p3, P3), (p4, P4), (p5, P5));
#[rustfmt::skip]
into_closure_many!((p0, P0), (p1, P1), (p2, P2), (p3, P3), (p4, P4), (p5, P5), (p6, P6));
#[rustfmt::skip]
into_closure_many!((p0, P0), (p1, P1), (p2, P2), (p3, P3), (p4, P4), (p5, P5), (p6, P6), (p7, P7));

// js-sys doesn't support closured with more than 7 arguments

// #[rustfmt::skip]
// into_closure_many!((p0, P0), (p1, P1), (p2, P2), (p3, P3), (p4, P4), (p5, P5), (p6, P6), (p7, P7), (p8, P8));
// #[rustfmt::skip]
// into_closure_many!((p0, P0), (p1, P1), (p2, P2), (p3, P3), (p4, P4), (p5, P5), (p6, P6), (p7, P7), (p8, P8), (p9, P9));
// #[rustfmt::skip]
// into_closure_many!((p0, P0), (p1, P1), (p2, P2), (p3, P3), (p4, P4), (p5, P5), (p6, P6), (p7, P7), (p8, P8), (p9, P9), (p10, P10));
// #[rustfmt::skip]
// into_closure_many!((p0, P0), (p1, P1), (p2, P2), (p3, P3), (p4, P4), (p5, P5), (p6, P6), (p7, P7), (p8, P8), (p9, P9), (p10, P10), (p11, P11));