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#[derive(Debug, Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord)]
26#[repr(transparent)]
27pub struct UntypedVal {
28 bits: u64,
31}
32
33impl UntypedVal {
34 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
130fn 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 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 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 pub fn i32_load(memory: &[u8], address: Self, offset: u32) -> Result<Self, TrapCode> {
184 Self::load::<i32>(memory, address, offset)
185 }
186
187 pub fn i64_load(memory: &[u8], address: Self, offset: u32) -> Result<Self, TrapCode> {
194 Self::load::<i64>(memory, address, offset)
195 }
196
197 pub fn f32_load(memory: &[u8], address: Self, offset: u32) -> Result<Self, TrapCode> {
204 Self::load::<F32>(memory, address, offset)
205 }
206
207 pub fn f64_load(memory: &[u8], address: Self, offset: u32) -> Result<Self, TrapCode> {
214 Self::load::<F64>(memory, address, offset)
215 }
216
217 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 pub fn i32_add(self, rhs: Self) -> Self {
531 self.execute_binary(rhs, <i32 as ArithmeticOps<i32>>::add)
532 }
533
534 pub fn i64_add(self, rhs: Self) -> Self {
536 self.execute_binary(rhs, <i64 as ArithmeticOps<i64>>::add)
537 }
538
539 pub fn i32_sub(self, rhs: Self) -> Self {
541 self.execute_binary(rhs, <i32 as ArithmeticOps<i32>>::sub)
542 }
543
544 pub fn i64_sub(self, rhs: Self) -> Self {
546 self.execute_binary(rhs, <i64 as ArithmeticOps<i64>>::sub)
547 }
548
549 pub fn i32_mul(self, rhs: Self) -> Self {
551 self.execute_binary(rhs, <i32 as ArithmeticOps<i32>>::mul)
552 }
553
554 pub fn i64_mul(self, rhs: Self) -> Self {
556 self.execute_binary(rhs, <i64 as ArithmeticOps<i64>>::mul)
557 }
558
559 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 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 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 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 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 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 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 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 pub fn i32_and(self, rhs: Self) -> Self {
641 self.execute_binary::<i32, _>(rhs, op!(&))
642 }
643
644 pub fn i64_and(self, rhs: Self) -> Self {
646 self.execute_binary::<i64, _>(rhs, op!(&))
647 }
648
649 pub fn i32_or(self, rhs: Self) -> Self {
651 self.execute_binary::<i32, _>(rhs, op!(|))
652 }
653
654 pub fn i64_or(self, rhs: Self) -> Self {
656 self.execute_binary::<i64, _>(rhs, op!(|))
657 }
658
659 pub fn i32_xor(self, rhs: Self) -> Self {
661 self.execute_binary::<i32, _>(rhs, op!(^))
662 }
663
664 pub fn i64_xor(self, rhs: Self) -> Self {
666 self.execute_binary::<i64, _>(rhs, op!(^))
667 }
668
669 pub fn i32_shl(self, rhs: Self) -> Self {
671 self.execute_binary::<i32, _>(rhs, |lhs, rhs| lhs.shl(rhs & 0x1F))
672 }
673
674 pub fn i64_shl(self, rhs: Self) -> Self {
676 self.execute_binary::<i64, _>(rhs, |lhs, rhs| lhs.shl(rhs & 0x3F))
677 }
678
679 pub fn i32_shr_s(self, rhs: Self) -> Self {
681 self.execute_binary::<i32, _>(rhs, |lhs, rhs| lhs.shr(rhs & 0x1F))
682 }
683
684 pub fn i64_shr_s(self, rhs: Self) -> Self {
686 self.execute_binary::<i64, _>(rhs, |lhs, rhs| lhs.shr(rhs & 0x3F))
687 }
688
689 pub fn i32_shr_u(self, rhs: Self) -> Self {
691 self.execute_binary::<u32, _>(rhs, |lhs, rhs| lhs.shr(rhs & 0x1F))
692 }
693
694 pub fn i64_shr_u(self, rhs: Self) -> Self {
696 self.execute_binary::<u64, _>(rhs, |lhs, rhs| lhs.shr(rhs & 0x3F))
697 }
698
699 pub fn i32_clz(self) -> Self {
701 self.execute_unary(<i32 as Integer<i32>>::leading_zeros)
702 }
703
704 pub fn i64_clz(self) -> Self {
706 self.execute_unary(<i64 as Integer<i64>>::leading_zeros)
707 }
708
709 pub fn i32_ctz(self) -> Self {
711 self.execute_unary(<i32 as Integer<i32>>::trailing_zeros)
712 }
713
714 pub fn i64_ctz(self) -> Self {
716 self.execute_unary(<i64 as Integer<i64>>::trailing_zeros)
717 }
718
719 pub fn i32_popcnt(self) -> Self {
721 self.execute_unary(<i32 as Integer<i32>>::count_ones)
722 }
723
724 pub fn i64_popcnt(self) -> Self {
726 self.execute_unary(<i64 as Integer<i64>>::count_ones)
727 }
728
729 pub fn i32_rotl(self, rhs: Self) -> Self {
731 self.execute_binary(rhs, <i32 as Integer<i32>>::rotl)
732 }
733
734 pub fn i64_rotl(self, rhs: Self) -> Self {
736 self.execute_binary(rhs, <i64 as Integer<i64>>::rotl)
737 }
738
739 pub fn i32_rotr(self, rhs: Self) -> Self {
741 self.execute_binary(rhs, <i32 as Integer<i32>>::rotr)
742 }
743
744 pub fn i64_rotr(self, rhs: Self) -> Self {
746 self.execute_binary(rhs, <i64 as Integer<i64>>::rotr)
747 }
748
749 pub fn i32_eqz(self) -> Self {
751 self.execute_unary::<i32, bool>(|value| value == 0)
752 }
753
754 pub fn i64_eqz(self) -> Self {
756 self.execute_unary::<i64, bool>(|value| value == 0)
757 }
758
759 pub fn i32_eq(self, rhs: Self) -> Self {
761 self.execute_binary::<i32, bool>(rhs, op!(==))
762 }
763
764 pub fn i64_eq(self, rhs: Self) -> Self {
766 self.execute_binary::<i64, bool>(rhs, op!(==))
767 }
768
769 pub fn f32_eq(self, rhs: Self) -> Self {
771 self.execute_binary::<F32, bool>(rhs, op!(==))
772 }
773
774 pub fn f64_eq(self, rhs: Self) -> Self {
776 self.execute_binary::<F64, bool>(rhs, op!(==))
777 }
778
779 pub fn i32_ne(self, rhs: Self) -> Self {
781 self.execute_binary::<i32, bool>(rhs, op!(!=))
782 }
783
784 pub fn i64_ne(self, rhs: Self) -> Self {
786 self.execute_binary::<i64, bool>(rhs, op!(!=))
787 }
788
789 pub fn f32_ne(self, rhs: Self) -> Self {
791 self.execute_binary::<F32, bool>(rhs, op!(!=))
792 }
793
794 pub fn f64_ne(self, rhs: Self) -> Self {
796 self.execute_binary::<F64, bool>(rhs, op!(!=))
797 }
798
799 pub fn i32_lt_s(self, rhs: Self) -> Self {
801 self.execute_binary::<i32, bool>(rhs, op!(<))
802 }
803
804 pub fn i64_lt_s(self, rhs: Self) -> Self {
806 self.execute_binary::<i64, bool>(rhs, op!(<))
807 }
808
809 pub fn i32_lt_u(self, rhs: Self) -> Self {
811 self.execute_binary::<u32, bool>(rhs, op!(<))
812 }
813
814 pub fn i64_lt_u(self, rhs: Self) -> Self {
816 self.execute_binary::<u64, bool>(rhs, op!(<))
817 }
818
819 pub fn f32_lt(self, rhs: Self) -> Self {
821 self.execute_binary::<F32, bool>(rhs, op!(<))
822 }
823
824 pub fn f64_lt(self, rhs: Self) -> Self {
826 self.execute_binary::<F64, bool>(rhs, op!(<))
827 }
828
829 pub fn i32_le_s(self, rhs: Self) -> Self {
831 self.execute_binary::<i32, bool>(rhs, op!(<=))
832 }
833
834 pub fn i64_le_s(self, rhs: Self) -> Self {
836 self.execute_binary::<i64, bool>(rhs, op!(<=))
837 }
838
839 pub fn i32_le_u(self, rhs: Self) -> Self {
841 self.execute_binary::<u32, bool>(rhs, op!(<=))
842 }
843
844 pub fn i64_le_u(self, rhs: Self) -> Self {
846 self.execute_binary::<u64, bool>(rhs, op!(<=))
847 }
848
849 pub fn f32_le(self, rhs: Self) -> Self {
851 self.execute_binary::<F32, bool>(rhs, op!(<=))
852 }
853
854 pub fn f64_le(self, rhs: Self) -> Self {
856 self.execute_binary::<F64, bool>(rhs, op!(<=))
857 }
858
859 pub fn i32_gt_s(self, rhs: Self) -> Self {
861 self.execute_binary::<i32, bool>(rhs, op!(>))
862 }
863
864 pub fn i64_gt_s(self, rhs: Self) -> Self {
866 self.execute_binary::<i64, bool>(rhs, op!(>))
867 }
868
869 pub fn i32_gt_u(self, rhs: Self) -> Self {
871 self.execute_binary::<u32, bool>(rhs, op!(>))
872 }
873
874 pub fn i64_gt_u(self, rhs: Self) -> Self {
876 self.execute_binary::<u64, bool>(rhs, op!(>))
877 }
878
879 pub fn f32_gt(self, rhs: Self) -> Self {
881 self.execute_binary::<F32, bool>(rhs, op!(>))
882 }
883
884 pub fn f64_gt(self, rhs: Self) -> Self {
886 self.execute_binary::<F64, bool>(rhs, op!(>))
887 }
888
889 pub fn i32_ge_s(self, rhs: Self) -> Self {
891 self.execute_binary::<i32, bool>(rhs, op!(>=))
892 }
893
894 pub fn i64_ge_s(self, rhs: Self) -> Self {
896 self.execute_binary::<i64, bool>(rhs, op!(>=))
897 }
898
899 pub fn i32_ge_u(self, rhs: Self) -> Self {
901 self.execute_binary::<u32, bool>(rhs, op!(>=))
902 }
903
904 pub fn i64_ge_u(self, rhs: Self) -> Self {
906 self.execute_binary::<u64, bool>(rhs, op!(>=))
907 }
908
909 pub fn f32_ge(self, rhs: Self) -> Self {
911 self.execute_binary::<F32, bool>(rhs, op!(>=))
912 }
913
914 pub fn f64_ge(self, rhs: Self) -> Self {
916 self.execute_binary::<F64, bool>(rhs, op!(>=))
917 }
918
919 pub fn f32_abs(self) -> Self {
921 self.execute_unary(<F32 as Float<F32>>::abs)
922 }
923
924 pub fn f32_neg(self) -> Self {
926 self.execute_unary(<F32 as Neg>::neg)
927 }
928
929 pub fn f32_ceil(self) -> Self {
931 self.execute_unary(<F32 as Float<F32>>::ceil)
932 }
933
934 pub fn f32_floor(self) -> Self {
936 self.execute_unary(<F32 as Float<F32>>::floor)
937 }
938
939 pub fn f32_trunc(self) -> Self {
941 self.execute_unary(<F32 as Float<F32>>::trunc)
942 }
943
944 pub fn f32_nearest(self) -> Self {
946 self.execute_unary(<F32 as Float<F32>>::nearest)
947 }
948
949 pub fn f32_sqrt(self) -> Self {
951 self.execute_unary(<F32 as Float<F32>>::sqrt)
952 }
953
954 pub fn f32_min(self, other: Self) -> Self {
956 self.execute_binary(other, <F32 as Float<F32>>::min)
957 }
958
959 pub fn f32_max(self, other: Self) -> Self {
961 self.execute_binary(other, <F32 as Float<F32>>::max)
962 }
963
964 pub fn f32_copysign(self, other: Self) -> Self {
966 self.execute_binary(other, <F32 as Float<F32>>::copysign)
967 }
968
969 pub fn f64_abs(self) -> Self {
971 self.execute_unary(<F64 as Float<F64>>::abs)
972 }
973
974 pub fn f64_neg(self) -> Self {
976 self.execute_unary(<F64 as Neg>::neg)
977 }
978
979 pub fn f64_ceil(self) -> Self {
981 self.execute_unary(<F64 as Float<F64>>::ceil)
982 }
983
984 pub fn f64_floor(self) -> Self {
986 self.execute_unary(<F64 as Float<F64>>::floor)
987 }
988
989 pub fn f64_trunc(self) -> Self {
991 self.execute_unary(<F64 as Float<F64>>::trunc)
992 }
993
994 pub fn f64_nearest(self) -> Self {
996 self.execute_unary(<F64 as Float<F64>>::nearest)
997 }
998
999 pub fn f64_sqrt(self) -> Self {
1001 self.execute_unary(<F64 as Float<F64>>::sqrt)
1002 }
1003
1004 pub fn f32_add(self, rhs: Self) -> Self {
1006 self.execute_binary(rhs, <F32 as ArithmeticOps<F32>>::add)
1007 }
1008
1009 pub fn f64_add(self, rhs: Self) -> Self {
1011 self.execute_binary(rhs, <F64 as ArithmeticOps<F64>>::add)
1012 }
1013
1014 pub fn f32_sub(self, rhs: Self) -> Self {
1016 self.execute_binary(rhs, <F32 as ArithmeticOps<F32>>::sub)
1017 }
1018
1019 pub fn f64_sub(self, rhs: Self) -> Self {
1021 self.execute_binary(rhs, <F64 as ArithmeticOps<F64>>::sub)
1022 }
1023
1024 pub fn f32_mul(self, rhs: Self) -> Self {
1026 self.execute_binary(rhs, <F32 as ArithmeticOps<F32>>::mul)
1027 }
1028
1029 pub fn f64_mul(self, rhs: Self) -> Self {
1031 self.execute_binary(rhs, <F64 as ArithmeticOps<F64>>::mul)
1032 }
1033
1034 pub fn f32_div(self, rhs: Self) -> Self {
1036 self.execute_binary(rhs, <F32 as Float<F32>>::div)
1037 }
1038
1039 pub fn f64_div(self, rhs: Self) -> Self {
1041 self.execute_binary(rhs, <F64 as Float<F64>>::div)
1042 }
1043
1044 pub fn f64_min(self, other: Self) -> Self {
1046 self.execute_binary(other, <F64 as Float<F64>>::min)
1047 }
1048
1049 pub fn f64_max(self, other: Self) -> Self {
1051 self.execute_binary(other, <F64 as Float<F64>>::max)
1052 }
1053
1054 pub fn f64_copysign(self, other: Self) -> Self {
1056 self.execute_binary(other, <F64 as Float<F64>>::copysign)
1057 }
1058
1059 pub fn i32_wrap_i64(self) -> Self {
1061 self.execute_unary(<i64 as WrapInto<i32>>::wrap_into)
1062 }
1063
1064 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 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 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 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 pub fn i64_extend_i32_s(self) -> Self {
1130 self.execute_unary(<i32 as ExtendInto<i64>>::extend_into)
1131 }
1132
1133 pub fn i64_extend_i32_u(self) -> Self {
1135 self.execute_unary(<u32 as ExtendInto<i64>>::extend_into)
1136 }
1137
1138 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 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 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 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 pub fn f32_convert_i32_s(self) -> Self {
1204 self.execute_unary(<i32 as ExtendInto<F32>>::extend_into)
1205 }
1206
1207 pub fn f32_convert_i32_u(self) -> Self {
1209 self.execute_unary(<u32 as ExtendInto<F32>>::extend_into)
1210 }
1211
1212 pub fn f32_convert_i64_s(self) -> Self {
1214 self.execute_unary(<i64 as WrapInto<F32>>::wrap_into)
1215 }
1216
1217 pub fn f32_convert_i64_u(self) -> Self {
1219 self.execute_unary(<u64 as WrapInto<F32>>::wrap_into)
1220 }
1221
1222 pub fn f32_demote_f64(self) -> Self {
1224 self.execute_unary(<F64 as WrapInto<F32>>::wrap_into)
1225 }
1226
1227 pub fn f64_convert_i32_s(self) -> Self {
1229 self.execute_unary(<i32 as ExtendInto<F64>>::extend_into)
1230 }
1231
1232 pub fn f64_convert_i32_u(self) -> Self {
1234 self.execute_unary(<u32 as ExtendInto<F64>>::extend_into)
1235 }
1236
1237 pub fn f64_convert_i64_s(self) -> Self {
1239 self.execute_unary(<i64 as ExtendInto<F64>>::extend_into)
1240 }
1241
1242 pub fn f64_convert_i64_u(self) -> Self {
1244 self.execute_unary(<u64 as ExtendInto<F64>>::extend_into)
1245 }
1246
1247 pub fn f64_promote_f32(self) -> Self {
1249 self.execute_unary(<F32 as ExtendInto<F64>>::extend_into)
1250 }
1251
1252 pub fn i32_extend8_s(self) -> Self {
1254 self.execute_unary(<i32 as SignExtendFrom<i8>>::sign_extend_from)
1255 }
1256
1257 pub fn i32_extend16_s(self) -> Self {
1259 self.execute_unary(<i32 as SignExtendFrom<i16>>::sign_extend_from)
1260 }
1261
1262 pub fn i64_extend8_s(self) -> Self {
1264 self.execute_unary(<i64 as SignExtendFrom<i8>>::sign_extend_from)
1265 }
1266
1267 pub fn i64_extend16_s(self) -> Self {
1269 self.execute_unary(<i64 as SignExtendFrom<i16>>::sign_extend_from)
1270 }
1271
1272 pub fn i64_extend32_s(self) -> Self {
1274 self.execute_unary(<i64 as SignExtendFrom<i32>>::sign_extend_from)
1275 }
1276
1277 pub fn i32_trunc_sat_f32_s(self) -> Self {
1279 self.execute_unary(<F32 as TruncateSaturateInto<i32>>::truncate_saturate_into)
1280 }
1281
1282 pub fn i32_trunc_sat_f32_u(self) -> Self {
1284 self.execute_unary(<F32 as TruncateSaturateInto<u32>>::truncate_saturate_into)
1285 }
1286
1287 pub fn i32_trunc_sat_f64_s(self) -> Self {
1289 self.execute_unary(<F64 as TruncateSaturateInto<i32>>::truncate_saturate_into)
1290 }
1291
1292 pub fn i32_trunc_sat_f64_u(self) -> Self {
1294 self.execute_unary(<F64 as TruncateSaturateInto<u32>>::truncate_saturate_into)
1295 }
1296
1297 pub fn i64_trunc_sat_f32_s(self) -> Self {
1299 self.execute_unary(<F32 as TruncateSaturateInto<i64>>::truncate_saturate_into)
1300 }
1301
1302 pub fn i64_trunc_sat_f32_u(self) -> Self {
1304 self.execute_unary(<F32 as TruncateSaturateInto<u64>>::truncate_saturate_into)
1305 }
1306
1307 pub fn i64_trunc_sat_f64_s(self) -> Self {
1309 self.execute_unary(<F64 as TruncateSaturateInto<i64>>::truncate_saturate_into)
1310 }
1311
1312 pub fn i64_trunc_sat_f64_u(self) -> Self {
1314 self.execute_unary(<F64 as TruncateSaturateInto<u64>>::truncate_saturate_into)
1315 }
1316}
1317
1318macro_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#[derive(Debug, Copy, Clone)]
1343pub enum UntypedError {
1344 InvalidLen,
1346}
1347
1348impl UntypedError {
1349 #[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 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 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
1402pub trait DecodeUntypedSlice: Sized {
1404 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
1452pub trait EncodeUntypedSlice {
1454 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);