1use super::{
2 super::engine::{FuncFinished, FuncParams, FuncResults},
3 TrampolineEntity,
4};
5use crate::{
6 core::{DecodeUntypedSlice, EncodeUntypedSlice, UntypedVal, ValType, F32, F64},
7 Caller,
8 Error,
9 ExternRef,
10 FuncRef,
11 FuncType,
12};
13use core::{array, iter::FusedIterator};
14
15pub trait IntoFunc<T, Params, Results>: Send + Sync + 'static {
17 #[doc(hidden)]
19 type Params: WasmTyList;
20 #[doc(hidden)]
22 type Results: WasmTyList;
23
24 #[doc(hidden)]
26 fn into_func(self) -> (FuncType, TrampolineEntity<T>);
27}
28
29macro_rules! impl_into_func {
30 ( $n:literal $( $tuple:ident )* ) => {
31 impl<T, F, $($tuple,)* R> IntoFunc<T, ($($tuple,)*), R> for F
32 where
33 F: Fn($($tuple),*) -> R,
34 F: Send + Sync + 'static,
35 $(
36 $tuple: WasmTy,
37 )*
38 R: WasmRet,
39 {
40 type Params = ($($tuple,)*);
41 type Results = <R as WasmRet>::Ok;
42
43 #[allow(non_snake_case)]
44 fn into_func(self) -> (FuncType, TrampolineEntity<T>) {
45 IntoFunc::into_func(
46 move |
47 _: Caller<'_, T>,
48 $(
49 $tuple: $tuple,
50 )*
51 | {
52 (self)($($tuple),*)
53 }
54 )
55 }
56 }
57
58 impl<T, F, $($tuple,)* R> IntoFunc<T, (Caller<'_, T>, $($tuple),*), R> for F
59 where
60 F: Fn(Caller<T>, $($tuple),*) -> R,
61 F: Send + Sync + 'static,
62 $(
63 $tuple: WasmTy,
64 )*
65 R: WasmRet,
66 {
67 type Params = ($($tuple,)*);
68 type Results = <R as WasmRet>::Ok;
69
70 #[allow(non_snake_case)]
71 fn into_func(self) -> (FuncType, TrampolineEntity<T>) {
72 let signature = FuncType::new(
73 <Self::Params as WasmTyList>::types(),
74 <Self::Results as WasmTyList>::types(),
75 );
76 let trampoline = TrampolineEntity::new(
77 move |caller: Caller<T>, params_results: FuncParams| -> Result<FuncFinished, Error> {
78 let (($($tuple,)*), func_results): (Self::Params, FuncResults) = params_results.decode_params();
79 let results: Self::Results =
80 (self)(caller, $($tuple),*).into_fallible()?;
81 Ok(func_results.encode_results(results))
82 },
83 );
84 (signature, trampoline)
85 }
86 }
87 };
88}
89for_each_tuple!(impl_into_func);
90
91pub trait WasmRet {
93 #[doc(hidden)]
94 type Ok: WasmTyList;
95
96 #[doc(hidden)]
97 fn into_fallible(self) -> Result<<Self as WasmRet>::Ok, Error>;
98}
99
100impl<T1> WasmRet for T1
101where
102 T1: WasmTy,
103{
104 type Ok = T1;
105
106 #[inline]
107 fn into_fallible(self) -> Result<Self::Ok, Error> {
108 Ok(self)
109 }
110}
111
112impl<T1> WasmRet for Result<T1, Error>
113where
114 T1: WasmTy,
115{
116 type Ok = T1;
117
118 #[inline]
119 fn into_fallible(self) -> Result<<Self as WasmRet>::Ok, Error> {
120 self
121 }
122}
123
124macro_rules! impl_wasm_return_type {
125 ( $n:literal $( $tuple:ident )* ) => {
126 impl<$($tuple),*> WasmRet for ($($tuple,)*)
127 where
128 $(
129 $tuple: WasmTy
130 ),*
131 {
132 type Ok = ($($tuple,)*);
133
134 #[inline]
135 fn into_fallible(self) -> Result<Self::Ok, Error> {
136 Ok(self)
137 }
138 }
139
140 impl<$($tuple),*> WasmRet for Result<($($tuple,)*), Error>
141 where
142 $(
143 $tuple: WasmTy
144 ),*
145 {
146 type Ok = ($($tuple,)*);
147
148 #[inline]
149 fn into_fallible(self) -> Result<<Self as WasmRet>::Ok, Error> {
150 self
151 }
152 }
153 };
154}
155for_each_tuple!(impl_wasm_return_type);
156
157pub trait WasmTy: From<UntypedVal> + Into<UntypedVal> + Send {
159 #[doc(hidden)]
161 fn ty() -> ValType;
162}
163
164macro_rules! impl_wasm_type {
165 ( $( type $rust_type:ty = $wasmi_type:ident );* $(;)? ) => {
166 $(
167 impl WasmTy for $rust_type {
168 #[inline]
169 fn ty() -> ValType {
170 ValType::$wasmi_type
171 }
172 }
173 )*
174 };
175}
176impl_wasm_type! {
177 type u32 = I32;
178 type u64 = I64;
179 type i32 = I32;
180 type i64 = I64;
181 type F32 = F32;
182 type F64 = F64;
183 type f32 = F32;
184 type f64 = F64;
185 type FuncRef = FuncRef;
186 type ExternRef = ExternRef;
187}
188
189pub trait WasmTyList: DecodeUntypedSlice + EncodeUntypedSlice + Sized + Send {
200 #[doc(hidden)]
202 const LEN: usize;
203
204 #[doc(hidden)]
206 type Types: IntoIterator<IntoIter = Self::TypesIter, Item = ValType>
207 + AsRef<[ValType]>
208 + AsMut<[ValType]>
209 + Copy
210 + Clone;
211
212 #[doc(hidden)]
214 type TypesIter: ExactSizeIterator<Item = ValType> + DoubleEndedIterator + FusedIterator;
215
216 #[doc(hidden)]
218 type Values: IntoIterator<IntoIter = Self::ValuesIter, Item = UntypedVal>
219 + AsRef<[UntypedVal]>
220 + AsMut<[UntypedVal]>
221 + Copy
222 + Clone;
223
224 #[doc(hidden)]
228 type ValuesIter: ExactSizeIterator<Item = UntypedVal> + DoubleEndedIterator + FusedIterator;
229
230 #[doc(hidden)]
232 fn types() -> Self::Types;
233
234 #[doc(hidden)]
236 fn values(self) -> Self::Values;
237
238 #[doc(hidden)]
242 fn from_values(values: &[UntypedVal]) -> Option<Self>;
243}
244
245impl<T1> WasmTyList for T1
246where
247 T1: WasmTy,
248{
249 const LEN: usize = 1;
250
251 type Types = [ValType; 1];
252 type TypesIter = array::IntoIter<ValType, 1>;
253 type Values = [UntypedVal; 1];
254 type ValuesIter = array::IntoIter<UntypedVal, 1>;
255
256 #[inline]
257 fn types() -> Self::Types {
258 [<T1 as WasmTy>::ty()]
259 }
260
261 #[inline]
262 fn values(self) -> Self::Values {
263 [<T1 as Into<UntypedVal>>::into(self)]
264 }
265
266 #[inline]
267 fn from_values(values: &[UntypedVal]) -> Option<Self> {
268 if let [value] = *values {
269 return Some(value.into());
270 }
271 None
272 }
273}
274
275macro_rules! impl_wasm_type_list {
276 ( $n:literal $( $tuple:ident )* ) => {
277 impl<$($tuple),*> WasmTyList for ($($tuple,)*)
278 where
279 $(
280 $tuple: WasmTy
281 ),*
282 {
283 const LEN: usize = $n;
284
285 type Types = [ValType; $n];
286 type TypesIter = array::IntoIter<ValType, $n>;
287 type Values = [UntypedVal; $n];
288 type ValuesIter = array::IntoIter<UntypedVal, $n>;
289
290 #[inline]
291 fn types() -> Self::Types {
292 [$(
293 <$tuple as WasmTy>::ty()
294 ),*]
295 }
296
297 #[inline]
298 #[allow(non_snake_case)]
299 fn values(self) -> Self::Values {
300 let ($($tuple,)*) = self;
301 [$(
302 <$tuple as Into<UntypedVal>>::into($tuple)
303 ),*]
304 }
305
306 #[inline]
307 #[allow(non_snake_case)]
308 fn from_values(values: &[UntypedVal]) -> Option<Self> {
309 if let [$($tuple),*] = *values {
310 return Some(
311 ( $( Into::into($tuple), )* )
312 )
313 }
314 None
315 }
316 }
317 };
318}
319for_each_tuple!(impl_wasm_type_list);
320
321#[cfg(test)]
322mod tests {
323 use super::*;
324 use std::string::String;
325
326 pub struct ImplementsWasmRet<T> {
328 marker: core::marker::PhantomData<fn() -> T>,
329 }
330 pub trait ImplementsWasmRetFallback {
332 const VALUE: bool = false;
333 }
334 impl<T> ImplementsWasmRetFallback for ImplementsWasmRet<T> {}
335 impl<T> ImplementsWasmRet<T>
337 where
338 T: WasmRet,
339 {
340 pub const VALUE: bool = true;
344 }
345 #[macro_export]
347 #[doc(hidden)]
348 macro_rules! implements_wasm_results {
349 ( $T:ty $(,)? ) => {{
350 #[allow(unused_imports)]
351 use ImplementsWasmRetFallback as _;
352 ImplementsWasmRet::<$T>::VALUE
353 }};
354 }
355
356 #[test]
357 fn into_func_trait_impls() {
358 assert!(!implements_wasm_results!(String));
359 assert!(!implements_wasm_results!(Option<i32>));
360 assert!(implements_wasm_results!(()));
361 assert!(implements_wasm_results!(i32));
362 assert!(implements_wasm_results!((i32,)));
363 assert!(implements_wasm_results!((i32, u32, i64, u64, F32, F64)));
364 assert!(implements_wasm_results!(Result<(), Error>));
365 assert!(implements_wasm_results!(Result<i32, Error>));
366 assert!(implements_wasm_results!(Result<(i32,), Error>));
367 assert!(implements_wasm_results!(Result<(i32, u32, i64, u64, F32, F64), Error>));
368 }
369}