soroban_wasmi_core/
untyped.rs

1use crate::{
2    ArithmeticOps,
3    ExtendInto,
4    Float,
5    Integer,
6    SignExtendFrom,
7    TrapCode,
8    TruncateSaturateInto,
9    TryTruncateInto,
10    Value,
11    ValueType,
12    WrapInto,
13    F32,
14    F64,
15};
16use core::{
17    fmt::{self, Display},
18    ops::{Neg, Shl, Shr},
19};
20
21/// An untyped [`Value`].
22///
23/// Provides a dense and simple interface to all functional Wasm operations.
24#[derive(Debug, Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord)]
25#[repr(transparent)]
26pub struct UntypedValue {
27    /// This inner value is required to have enough bits to represent
28    /// all fundamental WebAssembly types `i32`, `i64`, `f32` and `f64`.
29    bits: u64,
30}
31
32impl UntypedValue {
33    /// Returns the underlying bits of the [`UntypedValue`].
34    pub fn to_bits(self) -> u64 {
35        self.bits
36    }
37
38    /// Converts the [`UntypedValue`] into a [`Value`].
39    pub fn with_type(self, value_type: ValueType) -> Value {
40        match value_type {
41            ValueType::I32 => Value::I32(<_>::from(self)),
42            ValueType::I64 => Value::I64(<_>::from(self)),
43            ValueType::F32 => Value::F32(<_>::from(self)),
44            ValueType::F64 => Value::F64(<_>::from(self)),
45        }
46    }
47}
48
49macro_rules! impl_from_untyped_for_int {
50    ( $( $int:ty ),* $(,)? ) => {
51        $(
52            impl From<UntypedValue> for $int {
53                fn from(untyped: UntypedValue) -> Self {
54                    untyped.to_bits() as _
55                }
56            }
57        )*
58    };
59}
60impl_from_untyped_for_int!(i8, i16, i32, i64, u8, u16, u32, u64);
61
62macro_rules! impl_from_untyped_for_float {
63    ( $( $float:ty ),* $(,)? ) => {
64        $(
65            impl From<UntypedValue> for $float {
66                fn from(untyped: UntypedValue) -> Self {
67                    Self::from_bits(untyped.to_bits() as _)
68                }
69            }
70        )*
71    };
72}
73impl_from_untyped_for_float!(f32, f64, F32, F64);
74
75impl From<UntypedValue> for bool {
76    fn from(untyped: UntypedValue) -> Self {
77        untyped.to_bits() != 0
78    }
79}
80
81impl From<Value> for UntypedValue {
82    fn from(value: Value) -> Self {
83        match value {
84            Value::I32(value) => value.into(),
85            Value::I64(value) => value.into(),
86            Value::F32(value) => value.into(),
87            Value::F64(value) => value.into(),
88        }
89    }
90}
91
92macro_rules! impl_from_unsigned_prim {
93    ( $( $prim:ty ),* $(,)? ) => {
94        $(
95            impl From<$prim> for UntypedValue {
96                fn from(value: $prim) -> Self {
97                    Self { bits: value as _ }
98                }
99            }
100        )*
101    };
102}
103#[rustfmt::skip]
104impl_from_unsigned_prim!(
105    bool, u8, u16, u32, u64,
106);
107
108macro_rules! impl_from_signed_prim {
109    ( $( $prim:ty as $base:ty ),* $(,)? ) => {
110        $(
111            impl From<$prim> for UntypedValue {
112                fn from(value: $prim) -> Self {
113                    Self { bits: value as $base as _ }
114                }
115            }
116        )*
117    };
118}
119#[rustfmt::skip]
120impl_from_signed_prim!(
121    i8 as u8,
122    i16 as u16,
123    i32 as u32,
124    i64 as u64,
125);
126
127macro_rules! impl_from_float {
128    ( $( $float:ty ),* $(,)? ) => {
129        $(
130            impl From<$float> for UntypedValue {
131                fn from(value: $float) -> Self {
132                    Self {
133                        bits: value.to_bits() as _,
134                    }
135                }
136            }
137        )*
138    };
139}
140impl_from_float!(f32, f64, F32, F64);
141
142macro_rules! op {
143    ( $operator:tt ) => {{
144        |lhs, rhs| lhs $operator rhs
145    }};
146}
147
148impl UntypedValue {
149    /// Execute an infallible generic operation on `T` that returns an `R`.
150    fn execute_unary<T, R>(self, op: fn(T) -> R) -> Self
151    where
152        T: From<Self>,
153        R: Into<Self>,
154    {
155        op(T::from(self)).into()
156    }
157
158    /// Execute an infallible generic operation on `T` that returns an `R`.
159    fn try_execute_unary<T, R>(self, op: fn(T) -> Result<R, TrapCode>) -> Result<Self, TrapCode>
160    where
161        T: From<Self>,
162        R: Into<Self>,
163    {
164        op(T::from(self)).map(Into::into)
165    }
166
167    /// Execute an infallible generic operation on `T` that returns an `R`.
168    fn execute_binary<T, R>(self, rhs: Self, op: fn(T, T) -> R) -> Self
169    where
170        T: From<Self>,
171        R: Into<Self>,
172    {
173        op(T::from(self), T::from(rhs)).into()
174    }
175
176    /// Execute a fallible generic operation on `T` that returns an `R`.
177    fn try_execute_binary<T, R>(
178        self,
179        rhs: Self,
180        op: fn(T, T) -> Result<R, TrapCode>,
181    ) -> Result<Self, TrapCode>
182    where
183        T: From<Self>,
184        R: Into<Self>,
185    {
186        op(T::from(self), T::from(rhs)).map(Into::into)
187    }
188
189    /// Execute `i32.add` Wasm operation.
190    pub fn i32_add(self, rhs: Self) -> Self {
191        self.execute_binary(rhs, <i32 as ArithmeticOps<i32>>::add)
192    }
193
194    /// Execute `i64.add` Wasm operation.
195    pub fn i64_add(self, rhs: Self) -> Self {
196        self.execute_binary(rhs, <i64 as ArithmeticOps<i64>>::add)
197    }
198
199    /// Execute `i32.sub` Wasm operation.
200    pub fn i32_sub(self, rhs: Self) -> Self {
201        self.execute_binary(rhs, <i32 as ArithmeticOps<i32>>::sub)
202    }
203
204    /// Execute `i64.sub` Wasm operation.
205    pub fn i64_sub(self, rhs: Self) -> Self {
206        self.execute_binary(rhs, <i64 as ArithmeticOps<i64>>::sub)
207    }
208
209    /// Execute `i32.mul` Wasm operation.
210    pub fn i32_mul(self, rhs: Self) -> Self {
211        self.execute_binary(rhs, <i32 as ArithmeticOps<i32>>::mul)
212    }
213
214    /// Execute `i64.mul` Wasm operation.
215    pub fn i64_mul(self, rhs: Self) -> Self {
216        self.execute_binary(rhs, <i64 as ArithmeticOps<i64>>::mul)
217    }
218
219    /// Execute `i32.div_s` Wasm operation.
220    pub fn i32_div_s(self, rhs: Self) -> Result<Self, TrapCode> {
221        self.try_execute_binary(rhs, <i32 as ArithmeticOps<i32>>::div)
222    }
223
224    /// Execute `i64.div_s` Wasm operation.
225    pub fn i64_div_s(self, rhs: Self) -> Result<Self, TrapCode> {
226        self.try_execute_binary(rhs, <i64 as ArithmeticOps<i64>>::div)
227    }
228
229    /// Execute `i32.div_u` Wasm operation.
230    pub fn i32_div_u(self, rhs: Self) -> Result<Self, TrapCode> {
231        self.try_execute_binary(rhs, <u32 as ArithmeticOps<u32>>::div)
232    }
233
234    /// Execute `i64.div_u` Wasm operation.
235    pub fn i64_div_u(self, rhs: Self) -> Result<Self, TrapCode> {
236        self.try_execute_binary(rhs, <u64 as ArithmeticOps<u64>>::div)
237    }
238
239    /// Execute `i32.rem_s` Wasm operation.
240    pub fn i32_rem_s(self, rhs: Self) -> Result<Self, TrapCode> {
241        self.try_execute_binary(rhs, <i32 as Integer<i32>>::rem)
242    }
243
244    /// Execute `i64.rem_s` Wasm operation.
245    pub fn i64_rem_s(self, rhs: Self) -> Result<Self, TrapCode> {
246        self.try_execute_binary(rhs, <i64 as Integer<i64>>::rem)
247    }
248
249    /// Execute `i32.rem_u` Wasm operation.
250    pub fn i32_rem_u(self, rhs: Self) -> Result<Self, TrapCode> {
251        self.try_execute_binary(rhs, <u32 as Integer<u32>>::rem)
252    }
253
254    /// Execute `i64.rem_u` Wasm operation.
255    pub fn i64_rem_u(self, rhs: Self) -> Result<Self, TrapCode> {
256        self.try_execute_binary(rhs, <u64 as Integer<u64>>::rem)
257    }
258
259    /// Execute `i32.and` Wasm operation.
260    pub fn i32_and(self, rhs: Self) -> Self {
261        self.execute_binary::<i32, _>(rhs, op!(&))
262    }
263
264    /// Execute `i64.and` Wasm operation.
265    pub fn i64_and(self, rhs: Self) -> Self {
266        self.execute_binary::<i64, _>(rhs, op!(&))
267    }
268
269    /// Execute `i32.or` Wasm operation.
270    pub fn i32_or(self, rhs: Self) -> Self {
271        self.execute_binary::<i32, _>(rhs, op!(|))
272    }
273
274    /// Execute `i64.or` Wasm operation.
275    pub fn i64_or(self, rhs: Self) -> Self {
276        self.execute_binary::<i64, _>(rhs, op!(|))
277    }
278
279    /// Execute `i32.xor` Wasm operation.
280    pub fn i32_xor(self, rhs: Self) -> Self {
281        self.execute_binary::<i32, _>(rhs, op!(^))
282    }
283
284    /// Execute `i64.xor` Wasm operation.
285    pub fn i64_xor(self, rhs: Self) -> Self {
286        self.execute_binary::<i64, _>(rhs, op!(^))
287    }
288
289    /// Execute `i32.shl` Wasm operation.
290    pub fn i32_shl(self, rhs: Self) -> Self {
291        self.execute_binary::<i32, _>(rhs, |lhs, rhs| lhs.shl(rhs & 0x1F))
292    }
293
294    /// Execute `i64.shl` Wasm operation.
295    pub fn i64_shl(self, rhs: Self) -> Self {
296        self.execute_binary::<i64, _>(rhs, |lhs, rhs| lhs.shl(rhs & 0x3F))
297    }
298
299    /// Execute `i32.shr_s` Wasm operation.
300    pub fn i32_shr_s(self, rhs: Self) -> Self {
301        self.execute_binary::<i32, _>(rhs, |lhs, rhs| lhs.shr(rhs & 0x1F))
302    }
303
304    /// Execute `i64.shr_s` Wasm operation.
305    pub fn i64_shr_s(self, rhs: Self) -> Self {
306        self.execute_binary::<i64, _>(rhs, |lhs, rhs| lhs.shr(rhs & 0x3F))
307    }
308
309    /// Execute `i32.shr_u` Wasm operation.
310    pub fn i32_shr_u(self, rhs: Self) -> Self {
311        self.execute_binary::<u32, _>(rhs, |lhs, rhs| lhs.shr(rhs & 0x1F))
312    }
313
314    /// Execute `i64.shr_u` Wasm operation.
315    pub fn i64_shr_u(self, rhs: Self) -> Self {
316        self.execute_binary::<u64, _>(rhs, |lhs, rhs| lhs.shr(rhs & 0x3F))
317    }
318
319    /// Execute `i32.clz` Wasm operation.
320    pub fn i32_clz(self) -> Self {
321        self.execute_unary(<i32 as Integer<i32>>::leading_zeros)
322    }
323
324    /// Execute `i64.clz` Wasm operation.
325    pub fn i64_clz(self) -> Self {
326        self.execute_unary(<i64 as Integer<i64>>::leading_zeros)
327    }
328
329    /// Execute `i32.ctz` Wasm operation.
330    pub fn i32_ctz(self) -> Self {
331        self.execute_unary(<i32 as Integer<i32>>::trailing_zeros)
332    }
333
334    /// Execute `i64.ctz` Wasm operation.
335    pub fn i64_ctz(self) -> Self {
336        self.execute_unary(<i64 as Integer<i64>>::trailing_zeros)
337    }
338
339    /// Execute `i32.popcnt` Wasm operation.
340    pub fn i32_popcnt(self) -> Self {
341        self.execute_unary(<i32 as Integer<i32>>::count_ones)
342    }
343
344    /// Execute `i64.popcnt` Wasm operation.
345    pub fn i64_popcnt(self) -> Self {
346        self.execute_unary(<i64 as Integer<i64>>::count_ones)
347    }
348
349    /// Execute `i32.rotl` Wasm operation.
350    pub fn i32_rotl(self, rhs: Self) -> Self {
351        self.execute_binary(rhs, <i32 as Integer<i32>>::rotl)
352    }
353
354    /// Execute `i64.rotl` Wasm operation.
355    pub fn i64_rotl(self, rhs: Self) -> Self {
356        self.execute_binary(rhs, <i64 as Integer<i64>>::rotl)
357    }
358
359    /// Execute `i32.rotr` Wasm operation.
360    pub fn i32_rotr(self, rhs: Self) -> Self {
361        self.execute_binary(rhs, <i32 as Integer<i32>>::rotr)
362    }
363
364    /// Execute `i64.rotr` Wasm operation.
365    pub fn i64_rotr(self, rhs: Self) -> Self {
366        self.execute_binary(rhs, <i64 as Integer<i64>>::rotr)
367    }
368
369    /// Execute `i32.eqz` Wasm operation.
370    pub fn i32_eqz(self) -> Self {
371        self.execute_unary::<i32, bool>(|value| value == 0)
372    }
373
374    /// Execute `i64.eqz` Wasm operation.
375    pub fn i64_eqz(self) -> Self {
376        self.execute_unary::<i64, bool>(|value| value == 0)
377    }
378
379    /// Execute `i32.eq` Wasm operation.
380    pub fn i32_eq(self, rhs: Self) -> Self {
381        self.execute_binary::<i32, bool>(rhs, op!(==))
382    }
383
384    /// Execute `i64.eq` Wasm operation.
385    pub fn i64_eq(self, rhs: Self) -> Self {
386        self.execute_binary::<i64, bool>(rhs, op!(==))
387    }
388
389    /// Execute `f32.eq` Wasm operation.
390    pub fn f32_eq(self, rhs: Self) -> Self {
391        self.execute_binary::<F32, bool>(rhs, op!(==))
392    }
393
394    /// Execute `f64.eq` Wasm operation.
395    pub fn f64_eq(self, rhs: Self) -> Self {
396        self.execute_binary::<F64, bool>(rhs, op!(==))
397    }
398
399    /// Execute `i32.ne` Wasm operation.
400    pub fn i32_ne(self, rhs: Self) -> Self {
401        self.execute_binary::<i32, bool>(rhs, op!(!=))
402    }
403
404    /// Execute `i64.ne` Wasm operation.
405    pub fn i64_ne(self, rhs: Self) -> Self {
406        self.execute_binary::<i64, bool>(rhs, op!(!=))
407    }
408
409    /// Execute `f32.ne` Wasm operation.
410    pub fn f32_ne(self, rhs: Self) -> Self {
411        self.execute_binary::<F32, bool>(rhs, op!(!=))
412    }
413
414    /// Execute `f64.ne` Wasm operation.
415    pub fn f64_ne(self, rhs: Self) -> Self {
416        self.execute_binary::<F64, bool>(rhs, op!(!=))
417    }
418
419    /// Execute `i32.lt_s` Wasm operation.
420    pub fn i32_lt_s(self, rhs: Self) -> Self {
421        self.execute_binary::<i32, bool>(rhs, op!(<))
422    }
423
424    /// Execute `i64.lt_s` Wasm operation.
425    pub fn i64_lt_s(self, rhs: Self) -> Self {
426        self.execute_binary::<i64, bool>(rhs, op!(<))
427    }
428
429    /// Execute `i32.lt_u` Wasm operation.
430    pub fn i32_lt_u(self, rhs: Self) -> Self {
431        self.execute_binary::<u32, bool>(rhs, op!(<))
432    }
433
434    /// Execute `i64.lt_u` Wasm operation.
435    pub fn i64_lt_u(self, rhs: Self) -> Self {
436        self.execute_binary::<u64, bool>(rhs, op!(<))
437    }
438
439    /// Execute `f32.lt` Wasm operation.
440    pub fn f32_lt(self, rhs: Self) -> Self {
441        self.execute_binary::<F32, bool>(rhs, op!(<))
442    }
443
444    /// Execute `f64.lt` Wasm operation.
445    pub fn f64_lt(self, rhs: Self) -> Self {
446        self.execute_binary::<F64, bool>(rhs, op!(<))
447    }
448
449    /// Execute `i32.le_s` Wasm operation.
450    pub fn i32_le_s(self, rhs: Self) -> Self {
451        self.execute_binary::<i32, bool>(rhs, op!(<=))
452    }
453
454    /// Execute `i64.le_s` Wasm operation.
455    pub fn i64_le_s(self, rhs: Self) -> Self {
456        self.execute_binary::<i64, bool>(rhs, op!(<=))
457    }
458
459    /// Execute `i32.le_u` Wasm operation.
460    pub fn i32_le_u(self, rhs: Self) -> Self {
461        self.execute_binary::<u32, bool>(rhs, op!(<=))
462    }
463
464    /// Execute `i64.le_u` Wasm operation.
465    pub fn i64_le_u(self, rhs: Self) -> Self {
466        self.execute_binary::<u64, bool>(rhs, op!(<=))
467    }
468
469    /// Execute `f32.le` Wasm operation.
470    pub fn f32_le(self, rhs: Self) -> Self {
471        self.execute_binary::<F32, bool>(rhs, op!(<=))
472    }
473
474    /// Execute `f64.le` Wasm operation.
475    pub fn f64_le(self, rhs: Self) -> Self {
476        self.execute_binary::<F64, bool>(rhs, op!(<=))
477    }
478
479    /// Execute `i32.gt_s` Wasm operation.
480    pub fn i32_gt_s(self, rhs: Self) -> Self {
481        self.execute_binary::<i32, bool>(rhs, op!(>))
482    }
483
484    /// Execute `i64.gt_s` Wasm operation.
485    pub fn i64_gt_s(self, rhs: Self) -> Self {
486        self.execute_binary::<i64, bool>(rhs, op!(>))
487    }
488
489    /// Execute `i32.gt_u` Wasm operation.
490    pub fn i32_gt_u(self, rhs: Self) -> Self {
491        self.execute_binary::<u32, bool>(rhs, op!(>))
492    }
493
494    /// Execute `i64.gt_u` Wasm operation.
495    pub fn i64_gt_u(self, rhs: Self) -> Self {
496        self.execute_binary::<u64, bool>(rhs, op!(>))
497    }
498
499    /// Execute `f32.gt` Wasm operation.
500    pub fn f32_gt(self, rhs: Self) -> Self {
501        self.execute_binary::<F32, bool>(rhs, op!(>))
502    }
503
504    /// Execute `f64.gt` Wasm operation.
505    pub fn f64_gt(self, rhs: Self) -> Self {
506        self.execute_binary::<F64, bool>(rhs, op!(>))
507    }
508
509    /// Execute `i32.ge_s` Wasm operation.
510    pub fn i32_ge_s(self, rhs: Self) -> Self {
511        self.execute_binary::<i32, bool>(rhs, op!(>=))
512    }
513
514    /// Execute `i64.ge_s` Wasm operation.
515    pub fn i64_ge_s(self, rhs: Self) -> Self {
516        self.execute_binary::<i64, bool>(rhs, op!(>=))
517    }
518
519    /// Execute `i32.ge_u` Wasm operation.
520    pub fn i32_ge_u(self, rhs: Self) -> Self {
521        self.execute_binary::<u32, bool>(rhs, op!(>=))
522    }
523
524    /// Execute `i64.ge_u` Wasm operation.
525    pub fn i64_ge_u(self, rhs: Self) -> Self {
526        self.execute_binary::<u64, bool>(rhs, op!(>=))
527    }
528
529    /// Execute `f32.ge` Wasm operation.
530    pub fn f32_ge(self, rhs: Self) -> Self {
531        self.execute_binary::<F32, bool>(rhs, op!(>=))
532    }
533
534    /// Execute `f64.ge` Wasm operation.
535    pub fn f64_ge(self, rhs: Self) -> Self {
536        self.execute_binary::<F64, bool>(rhs, op!(>=))
537    }
538
539    /// Execute `f32.abs` Wasm operation.
540    pub fn f32_abs(self) -> Self {
541        self.execute_unary(<F32 as Float<F32>>::abs)
542    }
543
544    /// Execute `f32.neg` Wasm operation.
545    pub fn f32_neg(self) -> Self {
546        self.execute_unary(<F32 as Neg>::neg)
547    }
548
549    /// Execute `f32.ceil` Wasm operation.
550    pub fn f32_ceil(self) -> Self {
551        self.execute_unary(<F32 as Float<F32>>::ceil)
552    }
553
554    /// Execute `f32.floor` Wasm operation.
555    pub fn f32_floor(self) -> Self {
556        self.execute_unary(<F32 as Float<F32>>::floor)
557    }
558
559    /// Execute `f32.trunc` Wasm operation.
560    pub fn f32_trunc(self) -> Self {
561        self.execute_unary(<F32 as Float<F32>>::trunc)
562    }
563
564    /// Execute `f32.nearest` Wasm operation.
565    pub fn f32_nearest(self) -> Self {
566        self.execute_unary(<F32 as Float<F32>>::nearest)
567    }
568
569    /// Execute `f32.sqrt` Wasm operation.
570    pub fn f32_sqrt(self) -> Self {
571        self.execute_unary(<F32 as Float<F32>>::sqrt)
572    }
573
574    /// Execute `f32.min` Wasm operation.
575    pub fn f32_min(self, other: Self) -> Self {
576        self.execute_binary(other, <F32 as Float<F32>>::min)
577    }
578
579    /// Execute `f32.max` Wasm operation.
580    pub fn f32_max(self, other: Self) -> Self {
581        self.execute_binary(other, <F32 as Float<F32>>::max)
582    }
583
584    /// Execute `f32.copysign` Wasm operation.
585    pub fn f32_copysign(self, other: Self) -> Self {
586        self.execute_binary(other, <F32 as Float<F32>>::copysign)
587    }
588
589    /// Execute `f64.abs` Wasm operation.
590    pub fn f64_abs(self) -> Self {
591        self.execute_unary(<F64 as Float<F64>>::abs)
592    }
593
594    /// Execute `f64.neg` Wasm operation.
595    pub fn f64_neg(self) -> Self {
596        self.execute_unary(<F64 as Neg>::neg)
597    }
598
599    /// Execute `f64.ceil` Wasm operation.
600    pub fn f64_ceil(self) -> Self {
601        self.execute_unary(<F64 as Float<F64>>::ceil)
602    }
603
604    /// Execute `f64.floor` Wasm operation.
605    pub fn f64_floor(self) -> Self {
606        self.execute_unary(<F64 as Float<F64>>::floor)
607    }
608
609    /// Execute `f64.trunc` Wasm operation.
610    pub fn f64_trunc(self) -> Self {
611        self.execute_unary(<F64 as Float<F64>>::trunc)
612    }
613
614    /// Execute `f64.nearest` Wasm operation.
615    pub fn f64_nearest(self) -> Self {
616        self.execute_unary(<F64 as Float<F64>>::nearest)
617    }
618
619    /// Execute `f64.sqrt` Wasm operation.
620    pub fn f64_sqrt(self) -> Self {
621        self.execute_unary(<F64 as Float<F64>>::sqrt)
622    }
623
624    /// Execute `f32.add` Wasm operation.
625    pub fn f32_add(self, rhs: Self) -> Self {
626        self.execute_binary(rhs, <F32 as ArithmeticOps<F32>>::add)
627    }
628
629    /// Execute `f64.add` Wasm operation.
630    pub fn f64_add(self, rhs: Self) -> Self {
631        self.execute_binary(rhs, <F64 as ArithmeticOps<F64>>::add)
632    }
633
634    /// Execute `f32.sub` Wasm operation.
635    pub fn f32_sub(self, rhs: Self) -> Self {
636        self.execute_binary(rhs, <F32 as ArithmeticOps<F32>>::sub)
637    }
638
639    /// Execute `f64.sub` Wasm operation.
640    pub fn f64_sub(self, rhs: Self) -> Self {
641        self.execute_binary(rhs, <F64 as ArithmeticOps<F64>>::sub)
642    }
643
644    /// Execute `f32.mul` Wasm operation.
645    pub fn f32_mul(self, rhs: Self) -> Self {
646        self.execute_binary(rhs, <F32 as ArithmeticOps<F32>>::mul)
647    }
648
649    /// Execute `f64.mul` Wasm operation.
650    pub fn f64_mul(self, rhs: Self) -> Self {
651        self.execute_binary(rhs, <F64 as ArithmeticOps<F64>>::mul)
652    }
653
654    /// Execute `f32.div` Wasm operation.
655    pub fn f32_div(self, rhs: Self) -> Result<Self, TrapCode> {
656        self.try_execute_binary(rhs, <F32 as ArithmeticOps<F32>>::div)
657    }
658
659    /// Execute `f64.div` Wasm operation.
660    pub fn f64_div(self, rhs: Self) -> Result<Self, TrapCode> {
661        self.try_execute_binary(rhs, <F64 as ArithmeticOps<F64>>::div)
662    }
663
664    /// Execute `f64.min` Wasm operation.
665    pub fn f64_min(self, other: Self) -> Self {
666        self.execute_binary(other, <F64 as Float<F64>>::min)
667    }
668
669    /// Execute `f64.max` Wasm operation.
670    pub fn f64_max(self, other: Self) -> Self {
671        self.execute_binary(other, <F64 as Float<F64>>::max)
672    }
673
674    /// Execute `f64.copysign` Wasm operation.
675    pub fn f64_copysign(self, other: Self) -> Self {
676        self.execute_binary(other, <F64 as Float<F64>>::copysign)
677    }
678
679    /// Execute `i32.wrap_i64` Wasm operation.
680    pub fn i32_wrap_i64(self) -> Self {
681        self.execute_unary(<i64 as WrapInto<i32>>::wrap_into)
682    }
683
684    /// Execute `i32.trunc_f32_s` Wasm operation.
685    pub fn i32_trunc_f32_s(self) -> Result<Self, TrapCode> {
686        self.try_execute_unary(<F32 as TryTruncateInto<i32, TrapCode>>::try_truncate_into)
687    }
688
689    /// Execute `i32.trunc_f32_u` Wasm operation.
690    pub fn i32_trunc_f32_u(self) -> Result<Self, TrapCode> {
691        self.try_execute_unary(<F32 as TryTruncateInto<u32, TrapCode>>::try_truncate_into)
692    }
693
694    /// Execute `i32.trunc_f64_s` Wasm operation.
695    pub fn i32_trunc_f64_s(self) -> Result<Self, TrapCode> {
696        self.try_execute_unary(<F64 as TryTruncateInto<i32, TrapCode>>::try_truncate_into)
697    }
698
699    /// Execute `i32.trunc_f64_u` Wasm operation.
700    pub fn i32_trunc_f64_u(self) -> Result<Self, TrapCode> {
701        self.try_execute_unary(<F64 as TryTruncateInto<u32, TrapCode>>::try_truncate_into)
702    }
703
704    /// Execute `i64.extend_i32_s` Wasm operation.
705    pub fn i64_extend_i32_s(self) -> Self {
706        self.execute_unary(<i32 as ExtendInto<i64>>::extend_into)
707    }
708
709    /// Execute `i64.extend_i32_u` Wasm operation.
710    pub fn i64_extend_i32_u(self) -> Self {
711        self.execute_unary(<u32 as ExtendInto<i64>>::extend_into)
712    }
713
714    /// Execute `i64.trunc_f32_s` Wasm operation.
715    pub fn i64_trunc_f32_s(self) -> Result<Self, TrapCode> {
716        self.try_execute_unary(<F32 as TryTruncateInto<i64, TrapCode>>::try_truncate_into)
717    }
718
719    /// Execute `i64.trunc_f32_u` Wasm operation.
720    pub fn i64_trunc_f32_u(self) -> Result<Self, TrapCode> {
721        self.try_execute_unary(<F32 as TryTruncateInto<u64, TrapCode>>::try_truncate_into)
722    }
723
724    /// Execute `i64.trunc_f64_s` Wasm operation.
725    pub fn i64_trunc_f64_s(self) -> Result<Self, TrapCode> {
726        self.try_execute_unary(<F64 as TryTruncateInto<i64, TrapCode>>::try_truncate_into)
727    }
728
729    /// Execute `i64.trunc_f64_u` Wasm operation.
730    pub fn i64_trunc_f64_u(self) -> Result<Self, TrapCode> {
731        self.try_execute_unary(<F64 as TryTruncateInto<u64, TrapCode>>::try_truncate_into)
732    }
733
734    /// Execute `f32.convert_i32_s` Wasm operation.
735    pub fn f32_convert_i32_s(self) -> Self {
736        self.execute_unary(<i32 as ExtendInto<F32>>::extend_into)
737    }
738
739    /// Execute `f32.convert_i32_u` Wasm operation.
740    pub fn f32_convert_i32_u(self) -> Self {
741        self.execute_unary(<u32 as ExtendInto<F32>>::extend_into)
742    }
743
744    /// Execute `f32.convert_i64_s` Wasm operation.
745    pub fn f32_convert_i64_s(self) -> Self {
746        self.execute_unary(<i64 as WrapInto<F32>>::wrap_into)
747    }
748
749    /// Execute `f32.convert_i64_u` Wasm operation.
750    pub fn f32_convert_i64_u(self) -> Self {
751        self.execute_unary(<u64 as WrapInto<F32>>::wrap_into)
752    }
753
754    /// Execute `f32.demote_f64` Wasm operation.
755    pub fn f32_demote_f64(self) -> Self {
756        self.execute_unary(<F64 as WrapInto<F32>>::wrap_into)
757    }
758
759    /// Execute `f64.convert_i32_s` Wasm operation.
760    pub fn f64_convert_i32_s(self) -> Self {
761        self.execute_unary(<i32 as ExtendInto<F64>>::extend_into)
762    }
763
764    /// Execute `f64.convert_i32_u` Wasm operation.
765    pub fn f64_convert_i32_u(self) -> Self {
766        self.execute_unary(<u32 as ExtendInto<F64>>::extend_into)
767    }
768
769    /// Execute `f64.convert_i64_s` Wasm operation.
770    pub fn f64_convert_i64_s(self) -> Self {
771        self.execute_unary(<i64 as ExtendInto<F64>>::extend_into)
772    }
773
774    /// Execute `f64.convert_i64_u` Wasm operation.
775    pub fn f64_convert_i64_u(self) -> Self {
776        self.execute_unary(<u64 as ExtendInto<F64>>::extend_into)
777    }
778
779    /// Execute `f64.promote_f32` Wasm operation.
780    pub fn f64_promote_f32(self) -> Self {
781        self.execute_unary(<F32 as ExtendInto<F64>>::extend_into)
782    }
783
784    /// Execute `i32.extend8_s` Wasm operation.
785    pub fn i32_extend8_s(self) -> Self {
786        self.execute_unary(<i32 as SignExtendFrom<i8>>::sign_extend_from)
787    }
788
789    /// Execute `i32.extend16_s` Wasm operation.
790    pub fn i32_extend16_s(self) -> Self {
791        self.execute_unary(<i32 as SignExtendFrom<i16>>::sign_extend_from)
792    }
793
794    /// Execute `i64.extend8_s` Wasm operation.
795    pub fn i64_extend8_s(self) -> Self {
796        self.execute_unary(<i64 as SignExtendFrom<i8>>::sign_extend_from)
797    }
798
799    /// Execute `i64.extend16_s` Wasm operation.
800    pub fn i64_extend16_s(self) -> Self {
801        self.execute_unary(<i64 as SignExtendFrom<i16>>::sign_extend_from)
802    }
803
804    /// Execute `i64.extend32_s` Wasm operation.
805    pub fn i64_extend32_s(self) -> Self {
806        self.execute_unary(<i64 as SignExtendFrom<i32>>::sign_extend_from)
807    }
808
809    /// Execute `i32.trunc_sat_f32_s` Wasm operation.
810    pub fn i32_trunc_sat_f32_s(self) -> Self {
811        self.execute_unary(<F32 as TruncateSaturateInto<i32>>::truncate_saturate_into)
812    }
813
814    /// Execute `i32.trunc_sat_f32_u` Wasm operation.
815    pub fn i32_trunc_sat_f32_u(self) -> Self {
816        self.execute_unary(<F32 as TruncateSaturateInto<u32>>::truncate_saturate_into)
817    }
818
819    /// Execute `i32.trunc_sat_f64_s` Wasm operation.
820    pub fn i32_trunc_sat_f64_s(self) -> Self {
821        self.execute_unary(<F64 as TruncateSaturateInto<i32>>::truncate_saturate_into)
822    }
823
824    /// Execute `i32.trunc_sat_f64_u` Wasm operation.
825    pub fn i32_trunc_sat_f64_u(self) -> Self {
826        self.execute_unary(<F64 as TruncateSaturateInto<u32>>::truncate_saturate_into)
827    }
828
829    /// Execute `i64.trunc_sat_f32_s` Wasm operation.
830    pub fn i64_trunc_sat_f32_s(self) -> Self {
831        self.execute_unary(<F32 as TruncateSaturateInto<i64>>::truncate_saturate_into)
832    }
833
834    /// Execute `i64.trunc_sat_f32_u` Wasm operation.
835    pub fn i64_trunc_sat_f32_u(self) -> Self {
836        self.execute_unary(<F32 as TruncateSaturateInto<u64>>::truncate_saturate_into)
837    }
838
839    /// Execute `i64.trunc_sat_f64_s` Wasm operation.
840    pub fn i64_trunc_sat_f64_s(self) -> Self {
841        self.execute_unary(<F64 as TruncateSaturateInto<i64>>::truncate_saturate_into)
842    }
843
844    /// Execute `i64.trunc_sat_f64_u` Wasm operation.
845    pub fn i64_trunc_sat_f64_u(self) -> Self {
846        self.execute_unary(<F64 as TruncateSaturateInto<u64>>::truncate_saturate_into)
847    }
848}
849
850/// Macro to help implement generic trait implementations for tuple types.
851macro_rules! for_each_tuple {
852    ($mac:ident) => {
853        $mac!( 0 );
854        $mac!( 1 T1);
855        $mac!( 2 T1 T2);
856        $mac!( 3 T1 T2 T3);
857        $mac!( 4 T1 T2 T3 T4);
858        $mac!( 5 T1 T2 T3 T4 T5);
859        $mac!( 6 T1 T2 T3 T4 T5 T6);
860        $mac!( 7 T1 T2 T3 T4 T5 T6 T7);
861        $mac!( 8 T1 T2 T3 T4 T5 T6 T7 T8);
862        $mac!( 9 T1 T2 T3 T4 T5 T6 T7 T8 T9);
863        $mac!(10 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10);
864        $mac!(11 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11);
865        $mac!(12 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12);
866        $mac!(13 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13);
867        $mac!(14 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13 T14);
868        $mac!(15 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13 T14 T15);
869        $mac!(16 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13 T14 T15 T16);
870    }
871}
872
873/// An error that may occur upon encoding or decoding slices of [`UntypedValue`].
874#[derive(Debug, Copy, Clone)]
875pub enum UntypedError {
876    /// The [`UntypedValue`] slice length did not match.
877    InvalidLen {
878        /// Expected number of [`UntypedValue`] elements.
879        expected: usize,
880        /// Found number of [`UntypedValue`] elements.
881        found: usize,
882    },
883}
884
885impl UntypedError {
886    /// Creates a new `InvalidLen` [`UntypedError`].
887    #[cold]
888    pub fn invalid_len(expected: usize, found: usize) -> Self {
889        Self::InvalidLen { expected, found }
890    }
891}
892
893impl Display for UntypedError {
894    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
895        match self {
896            UntypedError::InvalidLen { expected, found } => {
897                write!(
898                    f,
899                    "encountered invalid length for untyped slice. \
900                     expected: {expected}, found: {found}"
901                )
902            }
903        }
904    }
905}
906
907impl UntypedValue {
908    /// Decodes the slice of [`UntypedValue`] as a value of type `T`.
909    ///
910    /// # Note
911    ///
912    /// `T` can either be a single type or a tuple of types depending
913    /// on the length of the `slice`.
914    ///
915    /// # Errors
916    ///
917    /// If the tuple length of `T` and the length of `slice` does not match.
918    pub fn decode_slice<T>(slice: &[Self]) -> Result<T, UntypedError>
919    where
920        T: DecodeUntypedSlice,
921    {
922        <T as DecodeUntypedSlice>::decode_untyped_slice(slice)
923    }
924
925    /// Encodes the slice of [`UntypedValue`] from the given value of type `T`.
926    ///
927    /// # Note
928    ///
929    /// `T` can either be a single type or a tuple of types depending
930    /// on the length of the `slice`.
931    ///
932    /// # Errors
933    ///
934    /// If the tuple length of `T` and the length of `slice` does not match.
935    pub fn encode_slice<T>(slice: &mut [Self], input: T) -> Result<(), UntypedError>
936    where
937        T: EncodeUntypedSlice,
938    {
939        <T as EncodeUntypedSlice>::encode_untyped_slice(input, slice)
940    }
941}
942
943/// Tuple types that allow to decode a slice of [`UntypedValue`].
944pub trait DecodeUntypedSlice: Sized {
945    /// Decodes the slice of [`UntypedValue`] as a value of type `Self`.
946    ///
947    /// # Note
948    ///
949    /// `Self` can either be a single type or a tuple of types depending
950    /// on the length of the `slice`.
951    ///
952    /// # Errors
953    ///
954    /// If the tuple length of `Self` and the length of `slice` does not match.
955    fn decode_untyped_slice(params: &[UntypedValue]) -> Result<Self, UntypedError>;
956}
957
958impl<T1> DecodeUntypedSlice for T1
959where
960    T1: From<UntypedValue>,
961{
962    fn decode_untyped_slice(results: &[UntypedValue]) -> Result<Self, UntypedError> {
963        if results.len() != 1 {
964            return Err(UntypedError::invalid_len(1, results.len()));
965        }
966        Ok(<T1 as From<UntypedValue>>::from(results[0]))
967    }
968}
969
970macro_rules! impl_decode_untyped_slice {
971    ( $n:literal $( $tuple:ident )* ) => {
972        impl<$($tuple),*> DecodeUntypedSlice for ($($tuple,)*)
973        where
974            $(
975                $tuple: From<UntypedValue>
976            ),*
977        {
978            #[allow(non_snake_case)]
979            fn decode_untyped_slice(results: &[UntypedValue]) -> Result<Self, UntypedError> {
980                match results {
981                    &[$($tuple),*] => Ok((
982                        $(
983                            <$tuple as From<UntypedValue>>::from($tuple),
984                        )*
985                    )),
986                    _unexpected => {
987                        Err(UntypedError::invalid_len($n, results.len()))
988                    }
989                }
990            }
991        }
992    };
993}
994for_each_tuple!(impl_decode_untyped_slice);
995
996/// Tuple types that allow to encode a slice of [`UntypedValue`].
997pub trait EncodeUntypedSlice {
998    /// Encodes the slice of [`UntypedValue`] from the given value of type `Self`.
999    ///
1000    /// # Note
1001    ///
1002    /// `Self` can either be a single type or a tuple of types depending
1003    /// on the length of the `slice`.
1004    ///
1005    /// # Errors
1006    ///
1007    /// If the tuple length of `Self` and the length of `slice` does not match.
1008    fn encode_untyped_slice(self, results: &mut [UntypedValue]) -> Result<(), UntypedError>;
1009}
1010
1011impl<T1> EncodeUntypedSlice for T1
1012where
1013    T1: Into<UntypedValue>,
1014{
1015    fn encode_untyped_slice(self, results: &mut [UntypedValue]) -> Result<(), UntypedError> {
1016        if results.len() != 1 {
1017            return Err(UntypedError::invalid_len(1, results.len()));
1018        }
1019        results[0] = self.into();
1020        Ok(())
1021    }
1022}
1023
1024macro_rules! impl_encode_untyped_slice {
1025    ( $n:literal $( $tuple:ident )* ) => {
1026        impl<$($tuple),*> EncodeUntypedSlice for ($($tuple,)*)
1027        where
1028            $(
1029                $tuple: Into<UntypedValue>
1030            ),*
1031        {
1032            #[allow(non_snake_case)]
1033            fn encode_untyped_slice(self, results: &mut [UntypedValue]) -> Result<(), UntypedError> {
1034                if results.len() != $n {
1035                    return Err(UntypedError::invalid_len($n, results.len()))
1036                }
1037                let ($($tuple,)*) = self;
1038                let converted: [UntypedValue; $n] = [
1039                    $(
1040                        <$tuple as Into<UntypedValue>>::into($tuple)
1041                    ),*
1042                ];
1043                results.copy_from_slice(&converted);
1044                Ok(())
1045            }
1046        }
1047    };
1048}
1049for_each_tuple!(impl_encode_untyped_slice);