wasm_bindgen/convert/
closures.rs

1#![allow(clippy::fn_to_numeric_cast)]
2
3use core::mem;
4
5use crate::convert::slices::WasmSlice;
6use crate::convert::RefFromWasmAbi;
7use crate::convert::{FromWasmAbi, IntoWasmAbi, ReturnWasmAbi, WasmAbi, WasmRet};
8use crate::describe::{inform, WasmDescribe, FUNCTION};
9use crate::throw_str;
10
11macro_rules! stack_closures {
12    ($( ($cnt:tt $invoke:ident $invoke_mut:ident $($var:ident $arg1:ident $arg2:ident $arg3:ident $arg4:ident)*) )*) => ($(
13        #[allow(coherence_leak_check)]
14        impl<$($var,)* R> IntoWasmAbi for &'_ (dyn Fn($($var),*) -> R + '_)
15            where $($var: FromWasmAbi,)*
16                  R: ReturnWasmAbi
17        {
18            type Abi = WasmSlice;
19
20            fn into_abi(self) -> WasmSlice {
21                unsafe {
22                    let (a, b): (usize, usize) = mem::transmute(self);
23                    WasmSlice { ptr: a as u32, len: b as u32 }
24                }
25            }
26        }
27
28        #[allow(non_snake_case)]
29        unsafe extern "C" fn $invoke<$($var: FromWasmAbi,)* R: ReturnWasmAbi>(
30            a: usize,
31            b: usize,
32            $(
33            $arg1: <$var::Abi as WasmAbi>::Prim1,
34            $arg2: <$var::Abi as WasmAbi>::Prim2,
35            $arg3: <$var::Abi as WasmAbi>::Prim3,
36            $arg4: <$var::Abi as WasmAbi>::Prim4,
37            )*
38        ) -> WasmRet<R::Abi> {
39            if a == 0 {
40                throw_str("closure invoked after being dropped");
41            }
42            // Scope all local variables before we call `return_abi` to
43            // ensure they're all destroyed as `return_abi` may throw
44            let ret = {
45                let f: &dyn Fn($($var),*) -> R = mem::transmute((a, b));
46                $(
47                    let $var = <$var as FromWasmAbi>::from_abi($var::Abi::join($arg1, $arg2, $arg3, $arg4));
48                )*
49                f($($var),*)
50            };
51            ret.return_abi().into()
52        }
53
54        #[allow(coherence_leak_check)]
55        impl<$($var,)* R> WasmDescribe for dyn Fn($($var),*) -> R + '_
56            where $($var: FromWasmAbi,)*
57                  R: ReturnWasmAbi
58        {
59            #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
60            fn describe() {
61                inform(FUNCTION);
62                inform($invoke::<$($var,)* R> as usize as u32);
63                inform($cnt);
64                $(<$var as WasmDescribe>::describe();)*
65                <R as WasmDescribe>::describe();
66                <R as WasmDescribe>::describe();
67            }
68        }
69
70        #[allow(coherence_leak_check)]
71        impl<$($var,)* R> IntoWasmAbi for &'_ mut (dyn FnMut($($var),*) -> R + '_)
72            where $($var: FromWasmAbi,)*
73                  R: ReturnWasmAbi
74        {
75            type Abi = WasmSlice;
76
77            fn into_abi(self) -> WasmSlice {
78                unsafe {
79                    let (a, b): (usize, usize) = mem::transmute(self);
80                    WasmSlice { ptr: a as u32, len: b as u32 }
81                }
82            }
83        }
84
85        #[allow(non_snake_case)]
86        unsafe extern "C" fn $invoke_mut<$($var: FromWasmAbi,)* R: ReturnWasmAbi>(
87            a: usize,
88            b: usize,
89            $(
90            $arg1: <$var::Abi as WasmAbi>::Prim1,
91            $arg2: <$var::Abi as WasmAbi>::Prim2,
92            $arg3: <$var::Abi as WasmAbi>::Prim3,
93            $arg4: <$var::Abi as WasmAbi>::Prim4,
94            )*
95        ) -> WasmRet<R::Abi> {
96            if a == 0 {
97                throw_str("closure invoked recursively or after being dropped");
98            }
99            // Scope all local variables before we call `return_abi` to
100            // ensure they're all destroyed as `return_abi` may throw
101            let ret = {
102                let f: &mut dyn FnMut($($var),*) -> R = mem::transmute((a, b));
103                $(
104                    let $var = <$var as FromWasmAbi>::from_abi($var::Abi::join($arg1, $arg2, $arg3, $arg4));
105                )*
106                f($($var),*)
107            };
108            ret.return_abi().into()
109        }
110
111        #[allow(coherence_leak_check)]
112        impl<$($var,)* R> WasmDescribe for dyn FnMut($($var),*) -> R + '_
113            where $($var: FromWasmAbi,)*
114                  R: ReturnWasmAbi
115        {
116            #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
117            fn describe() {
118                inform(FUNCTION);
119                inform($invoke_mut::<$($var,)* R> as usize as u32);
120                inform($cnt);
121                $(<$var as WasmDescribe>::describe();)*
122                <R as WasmDescribe>::describe();
123                <R as WasmDescribe>::describe();
124            }
125        }
126    )*)
127}
128
129stack_closures! {
130    (0 invoke0 invoke0_mut)
131    (1 invoke1 invoke1_mut A a1 a2 a3 a4)
132    (2 invoke2 invoke2_mut A a1 a2 a3 a4 B b1 b2 b3 b4)
133    (3 invoke3 invoke3_mut A a1 a2 a3 a4 B b1 b2 b3 b4 C c1 c2 c3 c4)
134    (4 invoke4 invoke4_mut A a1 a2 a3 a4 B b1 b2 b3 b4 C c1 c2 c3 c4 D d1 d2 d3 d4)
135    (5 invoke5 invoke5_mut 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)
136    (6 invoke6 invoke6_mut 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)
137    (7 invoke7 invoke7_mut 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)
138    (8 invoke8 invoke8_mut 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)
139}
140
141impl<A, R> IntoWasmAbi for &(dyn Fn(&A) -> R + '_)
142where
143    A: RefFromWasmAbi,
144    R: ReturnWasmAbi,
145{
146    type Abi = WasmSlice;
147
148    fn into_abi(self) -> WasmSlice {
149        unsafe {
150            let (a, b): (usize, usize) = mem::transmute(self);
151            WasmSlice {
152                ptr: a as u32,
153                len: b as u32,
154            }
155        }
156    }
157}
158
159#[allow(non_snake_case)]
160#[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
161unsafe extern "C" fn invoke1_ref<A: RefFromWasmAbi, R: ReturnWasmAbi>(
162    a: usize,
163    b: usize,
164    arg1: <A::Abi as WasmAbi>::Prim1,
165    arg2: <A::Abi as WasmAbi>::Prim2,
166    arg3: <A::Abi as WasmAbi>::Prim3,
167    arg4: <A::Abi as WasmAbi>::Prim4,
168) -> WasmRet<R::Abi> {
169    if a == 0 {
170        throw_str("closure invoked after being dropped");
171    }
172    // Scope all local variables before we call `return_abi` to
173    // ensure they're all destroyed as `return_abi` may throw
174    let ret = {
175        let f: &dyn Fn(&A) -> R = mem::transmute((a, b));
176        let arg = <A as RefFromWasmAbi>::ref_from_abi(A::Abi::join(arg1, arg2, arg3, arg4));
177        f(&*arg)
178    };
179    ret.return_abi().into()
180}
181
182impl<A, R> WasmDescribe for dyn Fn(&A) -> R + '_
183where
184    A: RefFromWasmAbi,
185    R: ReturnWasmAbi,
186{
187    #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
188    fn describe() {
189        inform(FUNCTION);
190        inform(invoke1_ref::<A, R> as usize as u32);
191        inform(1);
192        <&A as WasmDescribe>::describe();
193        <R as WasmDescribe>::describe();
194        <R as WasmDescribe>::describe();
195    }
196}
197
198impl<A, R> IntoWasmAbi for &mut (dyn FnMut(&A) -> R + '_)
199where
200    A: RefFromWasmAbi,
201    R: ReturnWasmAbi,
202{
203    type Abi = WasmSlice;
204
205    fn into_abi(self) -> WasmSlice {
206        unsafe {
207            let (a, b): (usize, usize) = mem::transmute(self);
208            WasmSlice {
209                ptr: a as u32,
210                len: b as u32,
211            }
212        }
213    }
214}
215
216#[allow(non_snake_case)]
217#[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
218unsafe extern "C" fn invoke1_mut_ref<A: RefFromWasmAbi, R: ReturnWasmAbi>(
219    a: usize,
220    b: usize,
221    arg1: <A::Abi as WasmAbi>::Prim1,
222    arg2: <A::Abi as WasmAbi>::Prim2,
223    arg3: <A::Abi as WasmAbi>::Prim3,
224    arg4: <A::Abi as WasmAbi>::Prim4,
225) -> WasmRet<R::Abi> {
226    if a == 0 {
227        throw_str("closure invoked recursively or after being dropped");
228    }
229    // Scope all local variables before we call `return_abi` to
230    // ensure they're all destroyed as `return_abi` may throw
231    let ret = {
232        let f: &mut dyn FnMut(&A) -> R = mem::transmute((a, b));
233        let arg = <A as RefFromWasmAbi>::ref_from_abi(A::Abi::join(arg1, arg2, arg3, arg4));
234        f(&*arg)
235    };
236    ret.return_abi().into()
237}
238
239impl<A, R> WasmDescribe for dyn FnMut(&A) -> R + '_
240where
241    A: RefFromWasmAbi,
242    R: ReturnWasmAbi,
243{
244    #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
245    fn describe() {
246        inform(FUNCTION);
247        inform(invoke1_mut_ref::<A, R> as usize as u32);
248        inform(1);
249        <&A as WasmDescribe>::describe();
250        <R as WasmDescribe>::describe();
251        <R as WasmDescribe>::describe();
252    }
253}