wasmi_core/
untyped.rs

1use crate::{
2    value::{LoadInto, StoreFrom},
3    ArithmeticOps,
4    ExtendInto,
5    Float,
6    Integer,
7    LittleEndianConvert,
8    SignExtendFrom,
9    TrapCode,
10    TruncateSaturateInto,
11    TryTruncateInto,
12    WrapInto,
13    F32,
14    F64,
15};
16use core::{
17    fmt::{self, Display},
18    ops::{Neg, Shl, Shr},
19};
20use paste::paste;
21
22/// An untyped value.
23///
24/// Provides a dense and simple interface to all functional Wasm operations.
25#[derive(Debug, Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord)]
26#[repr(transparent)]
27pub struct UntypedVal {
28    /// This inner value is required to have enough bits to represent
29    /// all fundamental WebAssembly types `i32`, `i64`, `f32` and `f64`.
30    bits: u64,
31}
32
33impl UntypedVal {
34    /// Returns the underlying bits of the [`UntypedVal`].
35    pub fn to_bits(self) -> u64 {
36        self.bits
37    }
38}
39
40macro_rules! impl_from_untyped_for_int {
41    ( $( $int:ty ),* $(,)? ) => {
42        $(
43            impl From<UntypedVal> for $int {
44                fn from(untyped: UntypedVal) -> Self {
45                    untyped.to_bits() as _
46                }
47            }
48        )*
49    };
50}
51impl_from_untyped_for_int!(i8, i16, i32, i64, u8, u16, u32, u64);
52
53macro_rules! impl_from_untyped_for_float {
54    ( $( $float:ty ),* $(,)? ) => {
55        $(
56            impl From<UntypedVal> for $float {
57                fn from(untyped: UntypedVal) -> Self {
58                    Self::from_bits(untyped.to_bits() as _)
59                }
60            }
61        )*
62    };
63}
64impl_from_untyped_for_float!(f32, f64, F32, F64);
65
66impl From<UntypedVal> for bool {
67    fn from(untyped: UntypedVal) -> Self {
68        untyped.to_bits() != 0
69    }
70}
71
72macro_rules! impl_from_unsigned_prim {
73    ( $( $prim:ty ),* $(,)? ) => {
74        $(
75            impl From<$prim> for UntypedVal {
76                #[allow(clippy::cast_lossless)]
77                fn from(value: $prim) -> Self {
78                    Self { bits: value as _ }
79                }
80            }
81        )*
82    };
83}
84#[rustfmt::skip]
85impl_from_unsigned_prim!(
86    bool, u8, u16, u32, u64,
87);
88
89macro_rules! impl_from_signed_prim {
90    ( $( $prim:ty as $base:ty ),* $(,)? ) => {
91        $(
92            impl From<$prim> for UntypedVal {
93                #[allow(clippy::cast_lossless)]
94                fn from(value: $prim) -> Self {
95                    Self { bits: u64::from(value as $base) }
96                }
97            }
98        )*
99    };
100}
101#[rustfmt::skip]
102impl_from_signed_prim!(
103    i8 as u8,
104    i16 as u16,
105    i32 as u32,
106    i64 as u64,
107);
108
109macro_rules! impl_from_float {
110    ( $( $float:ty ),* $(,)? ) => {
111        $(
112            impl From<$float> for UntypedVal {
113                fn from(value: $float) -> Self {
114                    Self {
115                        bits: u64::from(value.to_bits()),
116                    }
117                }
118            }
119        )*
120    };
121}
122impl_from_float!(f32, f64, F32, F64);
123
124macro_rules! op {
125    ( $operator:tt ) => {{
126        |lhs, rhs| lhs $operator rhs
127    }};
128}
129
130/// Calculates the effective address of a linear memory access.
131///
132/// # Errors
133///
134/// If the resulting effective address overflows.
135fn effective_address(address: u32, offset: u32) -> Result<usize, TrapCode> {
136    offset
137        .checked_add(address)
138        .map(|address| address as usize)
139        .ok_or(TrapCode::MemoryOutOfBounds)
140}
141
142impl UntypedVal {
143    /// Executes a generic `T.loadN_[s|u]` Wasm operation.
144    ///
145    /// # Errors
146    ///
147    /// - If `address + offset` overflows.
148    /// - If `address + offset` loads out of bounds from `memory`.
149    fn load_extend<T, U>(memory: &[u8], address: Self, offset: u32) -> Result<Self, TrapCode>
150    where
151        T: Into<Self>,
152        U: LittleEndianConvert + ExtendInto<T>,
153    {
154        let raw_address = u32::from(address);
155        let address = effective_address(raw_address, offset)?;
156        let mut buffer = <<U as LittleEndianConvert>::Bytes as Default>::default();
157        buffer.load_into(memory, address)?;
158        let value: Self = <U as LittleEndianConvert>::from_le_bytes(buffer)
159            .extend_into()
160            .into();
161        Ok(value)
162    }
163
164    /// Executes a generic `T.load` Wasm operation.
165    ///
166    /// # Errors
167    ///
168    /// - If `address + offset` overflows.
169    /// - If `address + offset` loads out of bounds from `memory`.
170    fn load<T>(memory: &[u8], address: Self, offset: u32) -> Result<Self, TrapCode>
171    where
172        T: LittleEndianConvert + ExtendInto<T> + Into<Self>,
173    {
174        Self::load_extend::<T, T>(memory, address, offset)
175    }
176
177    /// Executes the `i32.load` Wasm operation.
178    ///
179    /// # Errors
180    ///
181    /// - If `address + offset` overflows.
182    /// - If `address + offset` loads out of bounds from `memory`.
183    pub fn i32_load(memory: &[u8], address: Self, offset: u32) -> Result<Self, TrapCode> {
184        Self::load::<i32>(memory, address, offset)
185    }
186
187    /// Executes the `i64.load` Wasm operation.
188    ///
189    /// # Errors
190    ///
191    /// - If `address + offset` overflows.
192    /// - If `address + offset` loads out of bounds from `memory`.
193    pub fn i64_load(memory: &[u8], address: Self, offset: u32) -> Result<Self, TrapCode> {
194        Self::load::<i64>(memory, address, offset)
195    }
196
197    /// Executes the `f32.load` Wasm operation.
198    ///
199    /// # Errors
200    ///
201    /// - If `address + offset` overflows.
202    /// - If `address + offset` loads out of bounds from `memory`.
203    pub fn f32_load(memory: &[u8], address: Self, offset: u32) -> Result<Self, TrapCode> {
204        Self::load::<F32>(memory, address, offset)
205    }
206
207    /// Executes the `f64.load` Wasm operation.
208    ///
209    /// # Errors
210    ///
211    /// - If `address + offset` overflows.
212    /// - If `address + offset` loads out of bounds from `memory`.
213    pub fn f64_load(memory: &[u8], address: Self, offset: u32) -> Result<Self, TrapCode> {
214        Self::load::<F64>(memory, address, offset)
215    }
216
217    /// Executes the `i32.load8_s` Wasm operation.
218    ///
219    /// # Errors
220    ///
221    /// - If `address + offset` overflows.
222    /// - If `address + offset` loads out of bounds from `memory`.
223    pub fn i32_load8_s(memory: &[u8], address: Self, offset: u32) -> Result<Self, TrapCode> {
224        Self::load_extend::<i32, i8>(memory, address, offset)
225    }
226
227    /// Executes the `i32.load8_u` Wasm operation.
228    ///
229    /// # Errors
230    ///
231    /// - If `address + offset` overflows.
232    /// - If `address + offset` loads out of bounds from `memory`.
233    pub fn i32_load8_u(memory: &[u8], address: Self, offset: u32) -> Result<Self, TrapCode> {
234        Self::load_extend::<i32, u8>(memory, address, offset)
235    }
236
237    /// Executes the `i32.load16_s` Wasm operation.
238    ///
239    /// # Errors
240    ///
241    /// - If `address + offset` overflows.
242    /// - If `address + offset` loads out of bounds from `memory`.
243    pub fn i32_load16_s(memory: &[u8], address: Self, offset: u32) -> Result<Self, TrapCode> {
244        Self::load_extend::<i32, i16>(memory, address, offset)
245    }
246
247    /// Executes the `i32.load16_u` Wasm operation.
248    ///
249    /// # Errors
250    ///
251    /// - If `address + offset` overflows.
252    /// - If `address + offset` loads out of bounds from `memory`.
253    pub fn i32_load16_u(memory: &[u8], address: Self, offset: u32) -> Result<Self, TrapCode> {
254        Self::load_extend::<i32, u16>(memory, address, offset)
255    }
256
257    /// Executes the `i64.load8_s` Wasm operation.
258    ///
259    /// # Errors
260    ///
261    /// - If `address + offset` overflows.
262    /// - If `address + offset` loads out of bounds from `memory`.
263    pub fn i64_load8_s(memory: &[u8], address: Self, offset: u32) -> Result<Self, TrapCode> {
264        Self::load_extend::<i64, i8>(memory, address, offset)
265    }
266
267    /// Executes the `i64.load8_u` Wasm operation.
268    ///
269    /// # Errors
270    ///
271    /// - If `address + offset` overflows.
272    /// - If `address + offset` loads out of bounds from `memory`.
273    pub fn i64_load8_u(memory: &[u8], address: Self, offset: u32) -> Result<Self, TrapCode> {
274        Self::load_extend::<i64, u8>(memory, address, offset)
275    }
276
277    /// Executes the `i64.load16_s` Wasm operation.
278    ///
279    /// # Errors
280    ///
281    /// - If `address + offset` overflows.
282    /// - If `address + offset` loads out of bounds from `memory`.
283    pub fn i64_load16_s(memory: &[u8], address: Self, offset: u32) -> Result<Self, TrapCode> {
284        Self::load_extend::<i64, i16>(memory, address, offset)
285    }
286
287    /// Executes the `i64.load16_u` Wasm operation.
288    ///
289    /// # Errors
290    ///
291    /// - If `address + offset` overflows.
292    /// - If `address + offset` loads out of bounds from `memory`.
293    pub fn i64_load16_u(memory: &[u8], address: Self, offset: u32) -> Result<Self, TrapCode> {
294        Self::load_extend::<i64, u16>(memory, address, offset)
295    }
296
297    /// Executes the `i64.load32_s` Wasm operation.
298    ///
299    /// # Errors
300    ///
301    /// - If `address + offset` overflows.
302    /// - If `address + offset` loads out of bounds from `memory`.
303    pub fn i64_load32_s(memory: &[u8], address: Self, offset: u32) -> Result<Self, TrapCode> {
304        Self::load_extend::<i64, i32>(memory, address, offset)
305    }
306
307    /// Executes the `i64.load32_u` Wasm operation.
308    ///
309    /// # Errors
310    ///
311    /// - If `address + offset` overflows.
312    /// - If `address + offset` loads out of bounds from `memory`.
313    pub fn i64_load32_u(memory: &[u8], address: Self, offset: u32) -> Result<Self, TrapCode> {
314        Self::load_extend::<i64, u32>(memory, address, offset)
315    }
316
317    /// Executes a generic `T.store[N]` Wasm operation.
318    ///
319    /// # Errors
320    ///
321    /// - If `address + offset` overflows.
322    /// - If `address + offset` stores out of bounds from `memory`.
323    fn store_wrap<T, U>(
324        memory: &mut [u8],
325        address: Self,
326        offset: u32,
327        value: Self,
328    ) -> Result<(), TrapCode>
329    where
330        T: From<Self> + WrapInto<U>,
331        U: LittleEndianConvert,
332    {
333        let raw_address = u32::from(address);
334        let address = effective_address(raw_address, offset)?;
335        let wrapped = T::from(value).wrap_into();
336        let buffer = <U as LittleEndianConvert>::into_le_bytes(wrapped);
337        buffer.store_from(memory, address)?;
338        Ok(())
339    }
340
341    /// Executes a generic `T.store` Wasm operation.
342    ///
343    /// # Errors
344    ///
345    /// - If `address + offset` overflows.
346    /// - If `address + offset` stores out of bounds from `memory`.
347    fn store<T>(memory: &mut [u8], address: Self, offset: u32, value: Self) -> Result<(), TrapCode>
348    where
349        T: From<Self> + WrapInto<T> + LittleEndianConvert,
350    {
351        Self::store_wrap::<T, T>(memory, address, offset, value)
352    }
353
354    /// Executes the `i32.store` Wasm operation.
355    ///
356    /// # Errors
357    ///
358    /// - If `address + offset` overflows.
359    /// - If `address + offset` stores out of bounds from `memory`.
360    pub fn i32_store(
361        memory: &mut [u8],
362        address: Self,
363        offset: u32,
364        value: Self,
365    ) -> Result<(), TrapCode> {
366        Self::store::<i32>(memory, address, offset, value)
367    }
368
369    /// Executes the `i64.store` Wasm operation.
370    ///
371    /// # Errors
372    ///
373    /// - If `address + offset` overflows.
374    /// - If `address + offset` stores out of bounds from `memory`.
375    pub fn i64_store(
376        memory: &mut [u8],
377        address: Self,
378        offset: u32,
379        value: Self,
380    ) -> Result<(), TrapCode> {
381        Self::store::<i64>(memory, address, offset, value)
382    }
383
384    /// Executes the `f32.store` Wasm operation.
385    ///
386    /// # Errors
387    ///
388    /// - If `address + offset` overflows.
389    /// - If `address + offset` stores out of bounds from `memory`.
390    pub fn f32_store(
391        memory: &mut [u8],
392        address: Self,
393        offset: u32,
394        value: Self,
395    ) -> Result<(), TrapCode> {
396        Self::store::<F32>(memory, address, offset, value)
397    }
398
399    /// Executes the `f64.store` Wasm operation.
400    ///
401    /// # Errors
402    ///
403    /// - If `address + offset` overflows.
404    /// - If `address + offset` stores out of bounds from `memory`.
405    pub fn f64_store(
406        memory: &mut [u8],
407        address: Self,
408        offset: u32,
409        value: Self,
410    ) -> Result<(), TrapCode> {
411        Self::store::<F64>(memory, address, offset, value)
412    }
413
414    /// Executes the `i32.store8` Wasm operation.
415    ///
416    /// # Errors
417    ///
418    /// - If `address + offset` overflows.
419    /// - If `address + offset` stores out of bounds from `memory`.
420    pub fn i32_store8(
421        memory: &mut [u8],
422        address: Self,
423        offset: u32,
424        value: Self,
425    ) -> Result<(), TrapCode> {
426        Self::store_wrap::<i32, i8>(memory, address, offset, value)
427    }
428
429    /// Executes the `i32.store16` Wasm operation.
430    ///
431    /// # Errors
432    ///
433    /// - If `address + offset` overflows.
434    /// - If `address + offset` stores out of bounds from `memory`.
435    pub fn i32_store16(
436        memory: &mut [u8],
437        address: Self,
438        offset: u32,
439        value: Self,
440    ) -> Result<(), TrapCode> {
441        Self::store_wrap::<i32, i16>(memory, address, offset, value)
442    }
443
444    /// Executes the `i64.store8` Wasm operation.
445    ///
446    /// # Errors
447    ///
448    /// - If `address + offset` overflows.
449    /// - If `address + offset` stores out of bounds from `memory`.
450    pub fn i64_store8(
451        memory: &mut [u8],
452        address: Self,
453        offset: u32,
454        value: Self,
455    ) -> Result<(), TrapCode> {
456        Self::store_wrap::<i64, i8>(memory, address, offset, value)
457    }
458
459    /// Executes the `i64.store16` Wasm operation.
460    ///
461    /// # Errors
462    ///
463    /// - If `address + offset` overflows.
464    /// - If `address + offset` stores out of bounds from `memory`.
465    pub fn i64_store16(
466        memory: &mut [u8],
467        address: Self,
468        offset: u32,
469        value: Self,
470    ) -> Result<(), TrapCode> {
471        Self::store_wrap::<i64, i16>(memory, address, offset, value)
472    }
473
474    /// Executes the `i64.store32` Wasm operation.
475    ///
476    /// # Errors
477    ///
478    /// - If `address + offset` overflows.
479    /// - If `address + offset` stores out of bounds from `memory`.
480    pub fn i64_store32(
481        memory: &mut [u8],
482        address: Self,
483        offset: u32,
484        value: Self,
485    ) -> Result<(), TrapCode> {
486        Self::store_wrap::<i64, i32>(memory, address, offset, value)
487    }
488
489    /// Execute an infallible generic operation on `T` that returns an `R`.
490    fn execute_unary<T, R>(self, op: fn(T) -> R) -> Self
491    where
492        T: From<Self>,
493        R: Into<Self>,
494    {
495        op(T::from(self)).into()
496    }
497
498    /// Execute an infallible generic operation on `T` that returns an `R`.
499    fn try_execute_unary<T, R>(self, op: fn(T) -> Result<R, TrapCode>) -> Result<Self, TrapCode>
500    where
501        T: From<Self>,
502        R: Into<Self>,
503    {
504        op(T::from(self)).map(Into::into)
505    }
506
507    /// Execute an infallible generic operation on `T` that returns an `R`.
508    fn execute_binary<T, R>(self, rhs: Self, op: fn(T, T) -> R) -> Self
509    where
510        T: From<Self>,
511        R: Into<Self>,
512    {
513        op(T::from(self), T::from(rhs)).into()
514    }
515
516    /// Execute a fallible generic operation on `T` that returns an `R`.
517    fn try_execute_binary<T, R>(
518        self,
519        rhs: Self,
520        op: fn(T, T) -> Result<R, TrapCode>,
521    ) -> Result<Self, TrapCode>
522    where
523        T: From<Self>,
524        R: Into<Self>,
525    {
526        op(T::from(self), T::from(rhs)).map(Into::into)
527    }
528
529    /// Execute `i32.add` Wasm operation.
530    pub fn i32_add(self, rhs: Self) -> Self {
531        self.execute_binary(rhs, <i32 as ArithmeticOps<i32>>::add)
532    }
533
534    /// Execute `i64.add` Wasm operation.
535    pub fn i64_add(self, rhs: Self) -> Self {
536        self.execute_binary(rhs, <i64 as ArithmeticOps<i64>>::add)
537    }
538
539    /// Execute `i32.sub` Wasm operation.
540    pub fn i32_sub(self, rhs: Self) -> Self {
541        self.execute_binary(rhs, <i32 as ArithmeticOps<i32>>::sub)
542    }
543
544    /// Execute `i64.sub` Wasm operation.
545    pub fn i64_sub(self, rhs: Self) -> Self {
546        self.execute_binary(rhs, <i64 as ArithmeticOps<i64>>::sub)
547    }
548
549    /// Execute `i32.mul` Wasm operation.
550    pub fn i32_mul(self, rhs: Self) -> Self {
551        self.execute_binary(rhs, <i32 as ArithmeticOps<i32>>::mul)
552    }
553
554    /// Execute `i64.mul` Wasm operation.
555    pub fn i64_mul(self, rhs: Self) -> Self {
556        self.execute_binary(rhs, <i64 as ArithmeticOps<i64>>::mul)
557    }
558
559    /// Execute `i32.div_s` Wasm operation.
560    ///
561    /// # Errors
562    ///
563    /// - If `rhs` is equal to zero.
564    /// - If the operation result overflows.
565    pub fn i32_div_s(self, rhs: Self) -> Result<Self, TrapCode> {
566        self.try_execute_binary(rhs, <i32 as Integer<i32>>::div)
567    }
568
569    /// Execute `i64.div_s` Wasm operation.
570    ///
571    /// # Errors
572    ///
573    /// - If `rhs` is equal to zero.
574    /// - If the operation result overflows.
575    pub fn i64_div_s(self, rhs: Self) -> Result<Self, TrapCode> {
576        self.try_execute_binary(rhs, <i64 as Integer<i64>>::div)
577    }
578
579    /// Execute `i32.div_u` Wasm operation.
580    ///
581    /// # Errors
582    ///
583    /// - If `rhs` is equal to zero.
584    /// - If the operation result overflows.
585    pub fn i32_div_u(self, rhs: Self) -> Result<Self, TrapCode> {
586        self.try_execute_binary(rhs, <u32 as Integer<u32>>::div)
587    }
588
589    /// Execute `i64.div_u` Wasm operation.
590    ///
591    /// # Errors
592    ///
593    /// - If `rhs` is equal to zero.
594    /// - If the operation result overflows.
595    pub fn i64_div_u(self, rhs: Self) -> Result<Self, TrapCode> {
596        self.try_execute_binary(rhs, <u64 as Integer<u64>>::div)
597    }
598
599    /// Execute `i32.rem_s` Wasm operation.
600    ///
601    /// # Errors
602    ///
603    /// - If `rhs` is equal to zero.
604    /// - If the operation result overflows.
605    pub fn i32_rem_s(self, rhs: Self) -> Result<Self, TrapCode> {
606        self.try_execute_binary(rhs, <i32 as Integer<i32>>::rem)
607    }
608
609    /// Execute `i64.rem_s` Wasm operation.
610    ///
611    /// # Errors
612    ///
613    /// - If `rhs` is equal to zero.
614    /// - If the operation result overflows.
615    pub fn i64_rem_s(self, rhs: Self) -> Result<Self, TrapCode> {
616        self.try_execute_binary(rhs, <i64 as Integer<i64>>::rem)
617    }
618
619    /// Execute `i32.rem_u` Wasm operation.
620    ///
621    /// # Errors
622    ///
623    /// - If `rhs` is equal to zero.
624    /// - If the operation result overflows.
625    pub fn i32_rem_u(self, rhs: Self) -> Result<Self, TrapCode> {
626        self.try_execute_binary(rhs, <u32 as Integer<u32>>::rem)
627    }
628
629    /// Execute `i64.rem_u` Wasm operation.
630    ///
631    /// # Errors
632    ///
633    /// - If `rhs` is equal to zero.
634    /// - If the operation result overflows.
635    pub fn i64_rem_u(self, rhs: Self) -> Result<Self, TrapCode> {
636        self.try_execute_binary(rhs, <u64 as Integer<u64>>::rem)
637    }
638
639    /// Execute `i32.and` Wasm operation.
640    pub fn i32_and(self, rhs: Self) -> Self {
641        self.execute_binary::<i32, _>(rhs, op!(&))
642    }
643
644    /// Execute `i64.and` Wasm operation.
645    pub fn i64_and(self, rhs: Self) -> Self {
646        self.execute_binary::<i64, _>(rhs, op!(&))
647    }
648
649    /// Execute `i32.or` Wasm operation.
650    pub fn i32_or(self, rhs: Self) -> Self {
651        self.execute_binary::<i32, _>(rhs, op!(|))
652    }
653
654    /// Execute `i64.or` Wasm operation.
655    pub fn i64_or(self, rhs: Self) -> Self {
656        self.execute_binary::<i64, _>(rhs, op!(|))
657    }
658
659    /// Execute `i32.xor` Wasm operation.
660    pub fn i32_xor(self, rhs: Self) -> Self {
661        self.execute_binary::<i32, _>(rhs, op!(^))
662    }
663
664    /// Execute `i64.xor` Wasm operation.
665    pub fn i64_xor(self, rhs: Self) -> Self {
666        self.execute_binary::<i64, _>(rhs, op!(^))
667    }
668
669    /// Execute `i32.shl` Wasm operation.
670    pub fn i32_shl(self, rhs: Self) -> Self {
671        self.execute_binary::<i32, _>(rhs, |lhs, rhs| lhs.shl(rhs & 0x1F))
672    }
673
674    /// Execute `i64.shl` Wasm operation.
675    pub fn i64_shl(self, rhs: Self) -> Self {
676        self.execute_binary::<i64, _>(rhs, |lhs, rhs| lhs.shl(rhs & 0x3F))
677    }
678
679    /// Execute `i32.shr_s` Wasm operation.
680    pub fn i32_shr_s(self, rhs: Self) -> Self {
681        self.execute_binary::<i32, _>(rhs, |lhs, rhs| lhs.shr(rhs & 0x1F))
682    }
683
684    /// Execute `i64.shr_s` Wasm operation.
685    pub fn i64_shr_s(self, rhs: Self) -> Self {
686        self.execute_binary::<i64, _>(rhs, |lhs, rhs| lhs.shr(rhs & 0x3F))
687    }
688
689    /// Execute `i32.shr_u` Wasm operation.
690    pub fn i32_shr_u(self, rhs: Self) -> Self {
691        self.execute_binary::<u32, _>(rhs, |lhs, rhs| lhs.shr(rhs & 0x1F))
692    }
693
694    /// Execute `i64.shr_u` Wasm operation.
695    pub fn i64_shr_u(self, rhs: Self) -> Self {
696        self.execute_binary::<u64, _>(rhs, |lhs, rhs| lhs.shr(rhs & 0x3F))
697    }
698
699    /// Execute `i32.clz` Wasm operation.
700    pub fn i32_clz(self) -> Self {
701        self.execute_unary(<i32 as Integer<i32>>::leading_zeros)
702    }
703
704    /// Execute `i64.clz` Wasm operation.
705    pub fn i64_clz(self) -> Self {
706        self.execute_unary(<i64 as Integer<i64>>::leading_zeros)
707    }
708
709    /// Execute `i32.ctz` Wasm operation.
710    pub fn i32_ctz(self) -> Self {
711        self.execute_unary(<i32 as Integer<i32>>::trailing_zeros)
712    }
713
714    /// Execute `i64.ctz` Wasm operation.
715    pub fn i64_ctz(self) -> Self {
716        self.execute_unary(<i64 as Integer<i64>>::trailing_zeros)
717    }
718
719    /// Execute `i32.popcnt` Wasm operation.
720    pub fn i32_popcnt(self) -> Self {
721        self.execute_unary(<i32 as Integer<i32>>::count_ones)
722    }
723
724    /// Execute `i64.popcnt` Wasm operation.
725    pub fn i64_popcnt(self) -> Self {
726        self.execute_unary(<i64 as Integer<i64>>::count_ones)
727    }
728
729    /// Execute `i32.rotl` Wasm operation.
730    pub fn i32_rotl(self, rhs: Self) -> Self {
731        self.execute_binary(rhs, <i32 as Integer<i32>>::rotl)
732    }
733
734    /// Execute `i64.rotl` Wasm operation.
735    pub fn i64_rotl(self, rhs: Self) -> Self {
736        self.execute_binary(rhs, <i64 as Integer<i64>>::rotl)
737    }
738
739    /// Execute `i32.rotr` Wasm operation.
740    pub fn i32_rotr(self, rhs: Self) -> Self {
741        self.execute_binary(rhs, <i32 as Integer<i32>>::rotr)
742    }
743
744    /// Execute `i64.rotr` Wasm operation.
745    pub fn i64_rotr(self, rhs: Self) -> Self {
746        self.execute_binary(rhs, <i64 as Integer<i64>>::rotr)
747    }
748
749    /// Execute `i32.eqz` Wasm operation.
750    pub fn i32_eqz(self) -> Self {
751        self.execute_unary::<i32, bool>(|value| value == 0)
752    }
753
754    /// Execute `i64.eqz` Wasm operation.
755    pub fn i64_eqz(self) -> Self {
756        self.execute_unary::<i64, bool>(|value| value == 0)
757    }
758
759    /// Execute `i32.eq` Wasm operation.
760    pub fn i32_eq(self, rhs: Self) -> Self {
761        self.execute_binary::<i32, bool>(rhs, op!(==))
762    }
763
764    /// Execute `i64.eq` Wasm operation.
765    pub fn i64_eq(self, rhs: Self) -> Self {
766        self.execute_binary::<i64, bool>(rhs, op!(==))
767    }
768
769    /// Execute `f32.eq` Wasm operation.
770    pub fn f32_eq(self, rhs: Self) -> Self {
771        self.execute_binary::<F32, bool>(rhs, op!(==))
772    }
773
774    /// Execute `f64.eq` Wasm operation.
775    pub fn f64_eq(self, rhs: Self) -> Self {
776        self.execute_binary::<F64, bool>(rhs, op!(==))
777    }
778
779    /// Execute `i32.ne` Wasm operation.
780    pub fn i32_ne(self, rhs: Self) -> Self {
781        self.execute_binary::<i32, bool>(rhs, op!(!=))
782    }
783
784    /// Execute `i64.ne` Wasm operation.
785    pub fn i64_ne(self, rhs: Self) -> Self {
786        self.execute_binary::<i64, bool>(rhs, op!(!=))
787    }
788
789    /// Execute `f32.ne` Wasm operation.
790    pub fn f32_ne(self, rhs: Self) -> Self {
791        self.execute_binary::<F32, bool>(rhs, op!(!=))
792    }
793
794    /// Execute `f64.ne` Wasm operation.
795    pub fn f64_ne(self, rhs: Self) -> Self {
796        self.execute_binary::<F64, bool>(rhs, op!(!=))
797    }
798
799    /// Execute `i32.lt_s` Wasm operation.
800    pub fn i32_lt_s(self, rhs: Self) -> Self {
801        self.execute_binary::<i32, bool>(rhs, op!(<))
802    }
803
804    /// Execute `i64.lt_s` Wasm operation.
805    pub fn i64_lt_s(self, rhs: Self) -> Self {
806        self.execute_binary::<i64, bool>(rhs, op!(<))
807    }
808
809    /// Execute `i32.lt_u` Wasm operation.
810    pub fn i32_lt_u(self, rhs: Self) -> Self {
811        self.execute_binary::<u32, bool>(rhs, op!(<))
812    }
813
814    /// Execute `i64.lt_u` Wasm operation.
815    pub fn i64_lt_u(self, rhs: Self) -> Self {
816        self.execute_binary::<u64, bool>(rhs, op!(<))
817    }
818
819    /// Execute `f32.lt` Wasm operation.
820    pub fn f32_lt(self, rhs: Self) -> Self {
821        self.execute_binary::<F32, bool>(rhs, op!(<))
822    }
823
824    /// Execute `f64.lt` Wasm operation.
825    pub fn f64_lt(self, rhs: Self) -> Self {
826        self.execute_binary::<F64, bool>(rhs, op!(<))
827    }
828
829    /// Execute `i32.le_s` Wasm operation.
830    pub fn i32_le_s(self, rhs: Self) -> Self {
831        self.execute_binary::<i32, bool>(rhs, op!(<=))
832    }
833
834    /// Execute `i64.le_s` Wasm operation.
835    pub fn i64_le_s(self, rhs: Self) -> Self {
836        self.execute_binary::<i64, bool>(rhs, op!(<=))
837    }
838
839    /// Execute `i32.le_u` Wasm operation.
840    pub fn i32_le_u(self, rhs: Self) -> Self {
841        self.execute_binary::<u32, bool>(rhs, op!(<=))
842    }
843
844    /// Execute `i64.le_u` Wasm operation.
845    pub fn i64_le_u(self, rhs: Self) -> Self {
846        self.execute_binary::<u64, bool>(rhs, op!(<=))
847    }
848
849    /// Execute `f32.le` Wasm operation.
850    pub fn f32_le(self, rhs: Self) -> Self {
851        self.execute_binary::<F32, bool>(rhs, op!(<=))
852    }
853
854    /// Execute `f64.le` Wasm operation.
855    pub fn f64_le(self, rhs: Self) -> Self {
856        self.execute_binary::<F64, bool>(rhs, op!(<=))
857    }
858
859    /// Execute `i32.gt_s` Wasm operation.
860    pub fn i32_gt_s(self, rhs: Self) -> Self {
861        self.execute_binary::<i32, bool>(rhs, op!(>))
862    }
863
864    /// Execute `i64.gt_s` Wasm operation.
865    pub fn i64_gt_s(self, rhs: Self) -> Self {
866        self.execute_binary::<i64, bool>(rhs, op!(>))
867    }
868
869    /// Execute `i32.gt_u` Wasm operation.
870    pub fn i32_gt_u(self, rhs: Self) -> Self {
871        self.execute_binary::<u32, bool>(rhs, op!(>))
872    }
873
874    /// Execute `i64.gt_u` Wasm operation.
875    pub fn i64_gt_u(self, rhs: Self) -> Self {
876        self.execute_binary::<u64, bool>(rhs, op!(>))
877    }
878
879    /// Execute `f32.gt` Wasm operation.
880    pub fn f32_gt(self, rhs: Self) -> Self {
881        self.execute_binary::<F32, bool>(rhs, op!(>))
882    }
883
884    /// Execute `f64.gt` Wasm operation.
885    pub fn f64_gt(self, rhs: Self) -> Self {
886        self.execute_binary::<F64, bool>(rhs, op!(>))
887    }
888
889    /// Execute `i32.ge_s` Wasm operation.
890    pub fn i32_ge_s(self, rhs: Self) -> Self {
891        self.execute_binary::<i32, bool>(rhs, op!(>=))
892    }
893
894    /// Execute `i64.ge_s` Wasm operation.
895    pub fn i64_ge_s(self, rhs: Self) -> Self {
896        self.execute_binary::<i64, bool>(rhs, op!(>=))
897    }
898
899    /// Execute `i32.ge_u` Wasm operation.
900    pub fn i32_ge_u(self, rhs: Self) -> Self {
901        self.execute_binary::<u32, bool>(rhs, op!(>=))
902    }
903
904    /// Execute `i64.ge_u` Wasm operation.
905    pub fn i64_ge_u(self, rhs: Self) -> Self {
906        self.execute_binary::<u64, bool>(rhs, op!(>=))
907    }
908
909    /// Execute `f32.ge` Wasm operation.
910    pub fn f32_ge(self, rhs: Self) -> Self {
911        self.execute_binary::<F32, bool>(rhs, op!(>=))
912    }
913
914    /// Execute `f64.ge` Wasm operation.
915    pub fn f64_ge(self, rhs: Self) -> Self {
916        self.execute_binary::<F64, bool>(rhs, op!(>=))
917    }
918
919    /// Execute `f32.abs` Wasm operation.
920    pub fn f32_abs(self) -> Self {
921        self.execute_unary(<F32 as Float<F32>>::abs)
922    }
923
924    /// Execute `f32.neg` Wasm operation.
925    pub fn f32_neg(self) -> Self {
926        self.execute_unary(<F32 as Neg>::neg)
927    }
928
929    /// Execute `f32.ceil` Wasm operation.
930    pub fn f32_ceil(self) -> Self {
931        self.execute_unary(<F32 as Float<F32>>::ceil)
932    }
933
934    /// Execute `f32.floor` Wasm operation.
935    pub fn f32_floor(self) -> Self {
936        self.execute_unary(<F32 as Float<F32>>::floor)
937    }
938
939    /// Execute `f32.trunc` Wasm operation.
940    pub fn f32_trunc(self) -> Self {
941        self.execute_unary(<F32 as Float<F32>>::trunc)
942    }
943
944    /// Execute `f32.nearest` Wasm operation.
945    pub fn f32_nearest(self) -> Self {
946        self.execute_unary(<F32 as Float<F32>>::nearest)
947    }
948
949    /// Execute `f32.sqrt` Wasm operation.
950    pub fn f32_sqrt(self) -> Self {
951        self.execute_unary(<F32 as Float<F32>>::sqrt)
952    }
953
954    /// Execute `f32.min` Wasm operation.
955    pub fn f32_min(self, other: Self) -> Self {
956        self.execute_binary(other, <F32 as Float<F32>>::min)
957    }
958
959    /// Execute `f32.max` Wasm operation.
960    pub fn f32_max(self, other: Self) -> Self {
961        self.execute_binary(other, <F32 as Float<F32>>::max)
962    }
963
964    /// Execute `f32.copysign` Wasm operation.
965    pub fn f32_copysign(self, other: Self) -> Self {
966        self.execute_binary(other, <F32 as Float<F32>>::copysign)
967    }
968
969    /// Execute `f64.abs` Wasm operation.
970    pub fn f64_abs(self) -> Self {
971        self.execute_unary(<F64 as Float<F64>>::abs)
972    }
973
974    /// Execute `f64.neg` Wasm operation.
975    pub fn f64_neg(self) -> Self {
976        self.execute_unary(<F64 as Neg>::neg)
977    }
978
979    /// Execute `f64.ceil` Wasm operation.
980    pub fn f64_ceil(self) -> Self {
981        self.execute_unary(<F64 as Float<F64>>::ceil)
982    }
983
984    /// Execute `f64.floor` Wasm operation.
985    pub fn f64_floor(self) -> Self {
986        self.execute_unary(<F64 as Float<F64>>::floor)
987    }
988
989    /// Execute `f64.trunc` Wasm operation.
990    pub fn f64_trunc(self) -> Self {
991        self.execute_unary(<F64 as Float<F64>>::trunc)
992    }
993
994    /// Execute `f64.nearest` Wasm operation.
995    pub fn f64_nearest(self) -> Self {
996        self.execute_unary(<F64 as Float<F64>>::nearest)
997    }
998
999    /// Execute `f64.sqrt` Wasm operation.
1000    pub fn f64_sqrt(self) -> Self {
1001        self.execute_unary(<F64 as Float<F64>>::sqrt)
1002    }
1003
1004    /// Execute `f32.add` Wasm operation.
1005    pub fn f32_add(self, rhs: Self) -> Self {
1006        self.execute_binary(rhs, <F32 as ArithmeticOps<F32>>::add)
1007    }
1008
1009    /// Execute `f64.add` Wasm operation.
1010    pub fn f64_add(self, rhs: Self) -> Self {
1011        self.execute_binary(rhs, <F64 as ArithmeticOps<F64>>::add)
1012    }
1013
1014    /// Execute `f32.sub` Wasm operation.
1015    pub fn f32_sub(self, rhs: Self) -> Self {
1016        self.execute_binary(rhs, <F32 as ArithmeticOps<F32>>::sub)
1017    }
1018
1019    /// Execute `f64.sub` Wasm operation.
1020    pub fn f64_sub(self, rhs: Self) -> Self {
1021        self.execute_binary(rhs, <F64 as ArithmeticOps<F64>>::sub)
1022    }
1023
1024    /// Execute `f32.mul` Wasm operation.
1025    pub fn f32_mul(self, rhs: Self) -> Self {
1026        self.execute_binary(rhs, <F32 as ArithmeticOps<F32>>::mul)
1027    }
1028
1029    /// Execute `f64.mul` Wasm operation.
1030    pub fn f64_mul(self, rhs: Self) -> Self {
1031        self.execute_binary(rhs, <F64 as ArithmeticOps<F64>>::mul)
1032    }
1033
1034    /// Execute `f32.div` Wasm operation.
1035    pub fn f32_div(self, rhs: Self) -> Self {
1036        self.execute_binary(rhs, <F32 as Float<F32>>::div)
1037    }
1038
1039    /// Execute `f64.div` Wasm operation.
1040    pub fn f64_div(self, rhs: Self) -> Self {
1041        self.execute_binary(rhs, <F64 as Float<F64>>::div)
1042    }
1043
1044    /// Execute `f64.min` Wasm operation.
1045    pub fn f64_min(self, other: Self) -> Self {
1046        self.execute_binary(other, <F64 as Float<F64>>::min)
1047    }
1048
1049    /// Execute `f64.max` Wasm operation.
1050    pub fn f64_max(self, other: Self) -> Self {
1051        self.execute_binary(other, <F64 as Float<F64>>::max)
1052    }
1053
1054    /// Execute `f64.copysign` Wasm operation.
1055    pub fn f64_copysign(self, other: Self) -> Self {
1056        self.execute_binary(other, <F64 as Float<F64>>::copysign)
1057    }
1058
1059    /// Execute `i32.wrap_i64` Wasm operation.
1060    pub fn i32_wrap_i64(self) -> Self {
1061        self.execute_unary(<i64 as WrapInto<i32>>::wrap_into)
1062    }
1063
1064    /// Execute `i32.trunc_f32_s` Wasm operation.
1065    ///
1066    /// # Errors
1067    ///
1068    /// - If `self` is NaN (not a number).
1069    /// - If `self` is positive or negative infinity.
1070    /// - If the integer value of `self` is out of bounds of the target type.
1071    ///
1072    /// Read more about the failure cases in the [WebAssembly specification].
1073    ///
1074    /// [WebAssembly specification]:
1075    /// https://webassembly.github.io/spec/core/exec/numerics.html#op-trunc-s
1076    pub fn i32_trunc_f32_s(self) -> Result<Self, TrapCode> {
1077        self.try_execute_unary(<F32 as TryTruncateInto<i32, TrapCode>>::try_truncate_into)
1078    }
1079
1080    /// Execute `i32.trunc_f32_u` Wasm operation.
1081    ///
1082    /// # Errors
1083    ///
1084    /// - If `self` is NaN (not a number).
1085    /// - If `self` is positive or negative infinity.
1086    /// - If the integer value of `self` is out of bounds of the target type.
1087    ///
1088    /// Read more about the failure cases in the [WebAssembly specification].
1089    ///
1090    /// [WebAssembly specification]:
1091    /// https://webassembly.github.io/spec/core/exec/numerics.html#op-trunc-s
1092    pub fn i32_trunc_f32_u(self) -> Result<Self, TrapCode> {
1093        self.try_execute_unary(<F32 as TryTruncateInto<u32, TrapCode>>::try_truncate_into)
1094    }
1095
1096    /// Execute `i32.trunc_f64_s` Wasm operation.
1097    ///
1098    /// # Errors
1099    ///
1100    /// - If `self` is NaN (not a number).
1101    /// - If `self` is positive or negative infinity.
1102    /// - If the integer value of `self` is out of bounds of the target type.
1103    ///
1104    /// Read more about the failure cases in the [WebAssembly specification].
1105    ///
1106    /// [WebAssembly specification]:
1107    /// https://webassembly.github.io/spec/core/exec/numerics.html#op-trunc-s
1108    pub fn i32_trunc_f64_s(self) -> Result<Self, TrapCode> {
1109        self.try_execute_unary(<F64 as TryTruncateInto<i32, TrapCode>>::try_truncate_into)
1110    }
1111
1112    /// Execute `i32.trunc_f64_u` Wasm operation.
1113    ///
1114    /// # Errors
1115    ///
1116    /// - If `self` is NaN (not a number).
1117    /// - If `self` is positive or negative infinity.
1118    /// - If the integer value of `self` is out of bounds of the target type.
1119    ///
1120    /// Read more about the failure cases in the [WebAssembly specification].
1121    ///
1122    /// [WebAssembly specification]:
1123    /// https://webassembly.github.io/spec/core/exec/numerics.html#op-trunc-s
1124    pub fn i32_trunc_f64_u(self) -> Result<Self, TrapCode> {
1125        self.try_execute_unary(<F64 as TryTruncateInto<u32, TrapCode>>::try_truncate_into)
1126    }
1127
1128    /// Execute `i64.extend_i32_s` Wasm operation.
1129    pub fn i64_extend_i32_s(self) -> Self {
1130        self.execute_unary(<i32 as ExtendInto<i64>>::extend_into)
1131    }
1132
1133    /// Execute `i64.extend_i32_u` Wasm operation.
1134    pub fn i64_extend_i32_u(self) -> Self {
1135        self.execute_unary(<u32 as ExtendInto<i64>>::extend_into)
1136    }
1137
1138    /// Execute `i64.trunc_f32_s` Wasm operation.
1139    ///
1140    /// # Errors
1141    ///
1142    /// - If `self` is NaN (not a number).
1143    /// - If `self` is positive or negative infinity.
1144    /// - If the integer value of `self` is out of bounds of the target type.
1145    ///
1146    /// Read more about the failure cases in the [WebAssembly specification].
1147    ///
1148    /// [WebAssembly specification]:
1149    /// https://webassembly.github.io/spec/core/exec/numerics.html#op-trunc-s
1150    pub fn i64_trunc_f32_s(self) -> Result<Self, TrapCode> {
1151        self.try_execute_unary(<F32 as TryTruncateInto<i64, TrapCode>>::try_truncate_into)
1152    }
1153
1154    /// Execute `i64.trunc_f32_u` Wasm operation.
1155    ///
1156    /// # Errors
1157    ///
1158    /// - If `self` is NaN (not a number).
1159    /// - If `self` is positive or negative infinity.
1160    /// - If the integer value of `self` is out of bounds of the target type.
1161    ///
1162    /// Read more about the failure cases in the [WebAssembly specification].
1163    ///
1164    /// [WebAssembly specification]:
1165    /// https://webassembly.github.io/spec/core/exec/numerics.html#op-trunc-s
1166    pub fn i64_trunc_f32_u(self) -> Result<Self, TrapCode> {
1167        self.try_execute_unary(<F32 as TryTruncateInto<u64, TrapCode>>::try_truncate_into)
1168    }
1169
1170    /// Execute `i64.trunc_f64_s` Wasm operation.
1171    ///
1172    /// # Errors
1173    ///
1174    /// - If `self` is NaN (not a number).
1175    /// - If `self` is positive or negative infinity.
1176    /// - If the integer value of `self` is out of bounds of the target type.
1177    ///
1178    /// Read more about the failure cases in the [WebAssembly specification].
1179    ///
1180    /// [WebAssembly specification]:
1181    /// https://webassembly.github.io/spec/core/exec/numerics.html#op-trunc-s
1182    pub fn i64_trunc_f64_s(self) -> Result<Self, TrapCode> {
1183        self.try_execute_unary(<F64 as TryTruncateInto<i64, TrapCode>>::try_truncate_into)
1184    }
1185
1186    /// Execute `i64.trunc_f64_u` Wasm operation.
1187    ///
1188    /// # Errors
1189    ///
1190    /// - If `self` is NaN (not a number).
1191    /// - If `self` is positive or negative infinity.
1192    /// - If the integer value of `self` is out of bounds of the target type.
1193    ///
1194    /// Read more about the failure cases in the [WebAssembly specification].
1195    ///
1196    /// [WebAssembly specification]:
1197    /// https://webassembly.github.io/spec/core/exec/numerics.html#op-trunc-s
1198    pub fn i64_trunc_f64_u(self) -> Result<Self, TrapCode> {
1199        self.try_execute_unary(<F64 as TryTruncateInto<u64, TrapCode>>::try_truncate_into)
1200    }
1201
1202    /// Execute `f32.convert_i32_s` Wasm operation.
1203    pub fn f32_convert_i32_s(self) -> Self {
1204        self.execute_unary(<i32 as ExtendInto<F32>>::extend_into)
1205    }
1206
1207    /// Execute `f32.convert_i32_u` Wasm operation.
1208    pub fn f32_convert_i32_u(self) -> Self {
1209        self.execute_unary(<u32 as ExtendInto<F32>>::extend_into)
1210    }
1211
1212    /// Execute `f32.convert_i64_s` Wasm operation.
1213    pub fn f32_convert_i64_s(self) -> Self {
1214        self.execute_unary(<i64 as WrapInto<F32>>::wrap_into)
1215    }
1216
1217    /// Execute `f32.convert_i64_u` Wasm operation.
1218    pub fn f32_convert_i64_u(self) -> Self {
1219        self.execute_unary(<u64 as WrapInto<F32>>::wrap_into)
1220    }
1221
1222    /// Execute `f32.demote_f64` Wasm operation.
1223    pub fn f32_demote_f64(self) -> Self {
1224        self.execute_unary(<F64 as WrapInto<F32>>::wrap_into)
1225    }
1226
1227    /// Execute `f64.convert_i32_s` Wasm operation.
1228    pub fn f64_convert_i32_s(self) -> Self {
1229        self.execute_unary(<i32 as ExtendInto<F64>>::extend_into)
1230    }
1231
1232    /// Execute `f64.convert_i32_u` Wasm operation.
1233    pub fn f64_convert_i32_u(self) -> Self {
1234        self.execute_unary(<u32 as ExtendInto<F64>>::extend_into)
1235    }
1236
1237    /// Execute `f64.convert_i64_s` Wasm operation.
1238    pub fn f64_convert_i64_s(self) -> Self {
1239        self.execute_unary(<i64 as ExtendInto<F64>>::extend_into)
1240    }
1241
1242    /// Execute `f64.convert_i64_u` Wasm operation.
1243    pub fn f64_convert_i64_u(self) -> Self {
1244        self.execute_unary(<u64 as ExtendInto<F64>>::extend_into)
1245    }
1246
1247    /// Execute `f64.promote_f32` Wasm operation.
1248    pub fn f64_promote_f32(self) -> Self {
1249        self.execute_unary(<F32 as ExtendInto<F64>>::extend_into)
1250    }
1251
1252    /// Execute `i32.extend8_s` Wasm operation.
1253    pub fn i32_extend8_s(self) -> Self {
1254        self.execute_unary(<i32 as SignExtendFrom<i8>>::sign_extend_from)
1255    }
1256
1257    /// Execute `i32.extend16_s` Wasm operation.
1258    pub fn i32_extend16_s(self) -> Self {
1259        self.execute_unary(<i32 as SignExtendFrom<i16>>::sign_extend_from)
1260    }
1261
1262    /// Execute `i64.extend8_s` Wasm operation.
1263    pub fn i64_extend8_s(self) -> Self {
1264        self.execute_unary(<i64 as SignExtendFrom<i8>>::sign_extend_from)
1265    }
1266
1267    /// Execute `i64.extend16_s` Wasm operation.
1268    pub fn i64_extend16_s(self) -> Self {
1269        self.execute_unary(<i64 as SignExtendFrom<i16>>::sign_extend_from)
1270    }
1271
1272    /// Execute `i64.extend32_s` Wasm operation.
1273    pub fn i64_extend32_s(self) -> Self {
1274        self.execute_unary(<i64 as SignExtendFrom<i32>>::sign_extend_from)
1275    }
1276
1277    /// Execute `i32.trunc_sat_f32_s` Wasm operation.
1278    pub fn i32_trunc_sat_f32_s(self) -> Self {
1279        self.execute_unary(<F32 as TruncateSaturateInto<i32>>::truncate_saturate_into)
1280    }
1281
1282    /// Execute `i32.trunc_sat_f32_u` Wasm operation.
1283    pub fn i32_trunc_sat_f32_u(self) -> Self {
1284        self.execute_unary(<F32 as TruncateSaturateInto<u32>>::truncate_saturate_into)
1285    }
1286
1287    /// Execute `i32.trunc_sat_f64_s` Wasm operation.
1288    pub fn i32_trunc_sat_f64_s(self) -> Self {
1289        self.execute_unary(<F64 as TruncateSaturateInto<i32>>::truncate_saturate_into)
1290    }
1291
1292    /// Execute `i32.trunc_sat_f64_u` Wasm operation.
1293    pub fn i32_trunc_sat_f64_u(self) -> Self {
1294        self.execute_unary(<F64 as TruncateSaturateInto<u32>>::truncate_saturate_into)
1295    }
1296
1297    /// Execute `i64.trunc_sat_f32_s` Wasm operation.
1298    pub fn i64_trunc_sat_f32_s(self) -> Self {
1299        self.execute_unary(<F32 as TruncateSaturateInto<i64>>::truncate_saturate_into)
1300    }
1301
1302    /// Execute `i64.trunc_sat_f32_u` Wasm operation.
1303    pub fn i64_trunc_sat_f32_u(self) -> Self {
1304        self.execute_unary(<F32 as TruncateSaturateInto<u64>>::truncate_saturate_into)
1305    }
1306
1307    /// Execute `i64.trunc_sat_f64_s` Wasm operation.
1308    pub fn i64_trunc_sat_f64_s(self) -> Self {
1309        self.execute_unary(<F64 as TruncateSaturateInto<i64>>::truncate_saturate_into)
1310    }
1311
1312    /// Execute `i64.trunc_sat_f64_u` Wasm operation.
1313    pub fn i64_trunc_sat_f64_u(self) -> Self {
1314        self.execute_unary(<F64 as TruncateSaturateInto<u64>>::truncate_saturate_into)
1315    }
1316}
1317
1318/// Macro to help implement generic trait implementations for tuple types.
1319macro_rules! for_each_tuple {
1320    ($mac:ident) => {
1321        $mac!( 0 );
1322        $mac!( 1 T1);
1323        $mac!( 2 T1 T2);
1324        $mac!( 3 T1 T2 T3);
1325        $mac!( 4 T1 T2 T3 T4);
1326        $mac!( 5 T1 T2 T3 T4 T5);
1327        $mac!( 6 T1 T2 T3 T4 T5 T6);
1328        $mac!( 7 T1 T2 T3 T4 T5 T6 T7);
1329        $mac!( 8 T1 T2 T3 T4 T5 T6 T7 T8);
1330        $mac!( 9 T1 T2 T3 T4 T5 T6 T7 T8 T9);
1331        $mac!(10 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10);
1332        $mac!(11 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11);
1333        $mac!(12 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12);
1334        $mac!(13 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13);
1335        $mac!(14 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13 T14);
1336        $mac!(15 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13 T14 T15);
1337        $mac!(16 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13 T14 T15 T16);
1338    }
1339}
1340
1341/// An error that may occur upon encoding or decoding slices of [`UntypedVal`].
1342#[derive(Debug, Copy, Clone)]
1343pub enum UntypedError {
1344    /// The [`UntypedVal`] slice length did not match `Self`.
1345    InvalidLen,
1346}
1347
1348impl UntypedError {
1349    /// Creates a new `InvalidLen` [`UntypedError`].
1350    #[cold]
1351    pub fn invalid_len() -> Self {
1352        Self::InvalidLen
1353    }
1354}
1355
1356impl Display for UntypedError {
1357    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1358        match self {
1359            UntypedError::InvalidLen => {
1360                write!(f, "mismatched length of the untyped slice",)
1361            }
1362        }
1363    }
1364}
1365
1366impl UntypedVal {
1367    /// Decodes the slice of [`UntypedVal`] as a value of type `T`.
1368    ///
1369    /// # Note
1370    ///
1371    /// `T` can either be a single type or a tuple of types depending
1372    /// on the length of the `slice`.
1373    ///
1374    /// # Errors
1375    ///
1376    /// If the tuple length of `T` and the length of `slice` does not match.
1377    pub fn decode_slice<T>(slice: &[Self]) -> Result<T, UntypedError>
1378    where
1379        T: DecodeUntypedSlice,
1380    {
1381        <T as DecodeUntypedSlice>::decode_untyped_slice(slice)
1382    }
1383
1384    /// Encodes the slice of [`UntypedVal`] from the given value of type `T`.
1385    ///
1386    /// # Note
1387    ///
1388    /// `T` can either be a single type or a tuple of types depending
1389    /// on the length of the `slice`.
1390    ///
1391    /// # Errors
1392    ///
1393    /// If the tuple length of `T` and the length of `slice` does not match.
1394    pub fn encode_slice<T>(slice: &mut [Self], input: T) -> Result<(), UntypedError>
1395    where
1396        T: EncodeUntypedSlice,
1397    {
1398        <T as EncodeUntypedSlice>::encode_untyped_slice(input, slice)
1399    }
1400}
1401
1402/// Tuple types that allow to decode a slice of [`UntypedVal`].
1403pub trait DecodeUntypedSlice: Sized {
1404    /// Decodes the slice of [`UntypedVal`] as a value of type `Self`.
1405    ///
1406    /// # Note
1407    ///
1408    /// `Self` can either be a single type or a tuple of types depending
1409    /// on the length of the `slice`.
1410    ///
1411    /// # Errors
1412    ///
1413    /// If the tuple length of `Self` and the length of `slice` does not match.
1414    fn decode_untyped_slice(params: &[UntypedVal]) -> Result<Self, UntypedError>;
1415}
1416
1417impl<T1> DecodeUntypedSlice for T1
1418where
1419    T1: From<UntypedVal>,
1420{
1421    #[inline]
1422    fn decode_untyped_slice(results: &[UntypedVal]) -> Result<Self, UntypedError> {
1423        <(T1,) as DecodeUntypedSlice>::decode_untyped_slice(results).map(|t| t.0)
1424    }
1425}
1426
1427macro_rules! impl_decode_untyped_slice {
1428    ( $n:literal $( $tuple:ident )* ) => {
1429        impl<$($tuple),*> DecodeUntypedSlice for ($($tuple,)*)
1430        where
1431            $(
1432                $tuple: From<UntypedVal>
1433            ),*
1434        {
1435            #[allow(non_snake_case)]
1436            #[inline]
1437            fn decode_untyped_slice(results: &[UntypedVal]) -> Result<Self, UntypedError> {
1438                match results {
1439                    &[ $($tuple),* ] => Ok((
1440                        $(
1441                            <$tuple as From<UntypedVal>>::from($tuple),
1442                        )*
1443                    )),
1444                    _ => Err(UntypedError::invalid_len()),
1445                }
1446            }
1447        }
1448    };
1449}
1450for_each_tuple!(impl_decode_untyped_slice);
1451
1452/// Tuple types that allow to encode a slice of [`UntypedVal`].
1453pub trait EncodeUntypedSlice {
1454    /// Encodes the slice of [`UntypedVal`] from the given value of type `Self`.
1455    ///
1456    /// # Note
1457    ///
1458    /// `Self` can either be a single type or a tuple of types depending
1459    /// on the length of the `slice`.
1460    ///
1461    /// # Errors
1462    ///
1463    /// If the tuple length of `Self` and the length of `slice` does not match.
1464    fn encode_untyped_slice(self, results: &mut [UntypedVal]) -> Result<(), UntypedError>;
1465}
1466
1467impl<T1> EncodeUntypedSlice for T1
1468where
1469    T1: Into<UntypedVal>,
1470{
1471    #[inline]
1472    fn encode_untyped_slice(self, results: &mut [UntypedVal]) -> Result<(), UntypedError> {
1473        <(T1,) as EncodeUntypedSlice>::encode_untyped_slice((self,), results)
1474    }
1475}
1476
1477macro_rules! impl_encode_untyped_slice {
1478    ( $n:literal $( $tuple:ident )* ) => {
1479        paste! {
1480            impl<$($tuple),*> EncodeUntypedSlice for ($($tuple,)*)
1481            where
1482                $(
1483                    $tuple: Into<UntypedVal>
1484                ),*
1485            {
1486                #[allow(non_snake_case)]
1487                #[inline]
1488                fn encode_untyped_slice(self, results: &mut [UntypedVal]) -> Result<(), UntypedError> {
1489                    match results {
1490                        [ $( [< _results_ $tuple >] ,)* ] => {
1491                            let ( $( [< _self_ $tuple >] ,)* ) = self;
1492                            $(
1493                                *[< _results_ $tuple >] = <$tuple as Into<UntypedVal>>::into([< _self_ $tuple >]);
1494                            )*
1495                            Ok(())
1496                        }
1497                        _ => Err(UntypedError::invalid_len())
1498                    }
1499                }
1500            }
1501        }
1502    };
1503}
1504for_each_tuple!(impl_encode_untyped_slice);