1use crate::{
2 nan_preserving_float::{F32, F64},
3 TrapCode,
4};
5use core::{f32, i32, i64, u32, u64};
6
7#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
13pub enum ValueType {
14 I32,
16 I64,
18 F32,
20 F64,
22 FuncRef,
24 ExternRef,
26}
27
28impl ValueType {
29 pub fn is_num(&self) -> bool {
34 matches!(self, Self::I32 | Self::I64 | Self::F32 | Self::F64)
35 }
36
37 pub fn is_ref(&self) -> bool {
41 matches!(self, Self::ExternRef | Self::FuncRef)
42 }
43}
44
45pub trait WrapInto<T> {
47 fn wrap_into(self) -> T;
49}
50
51pub trait TryTruncateInto<T, E> {
58 fn try_truncate_into(self) -> Result<T, E>;
66}
67
68pub trait TruncateSaturateInto<T> {
80 fn truncate_saturate_into(self) -> T;
82}
83
84pub trait ExtendInto<T> {
86 fn extend_into(self) -> T;
88}
89
90pub trait SignExtendFrom<T> {
92 fn sign_extend_from(self) -> Self;
94}
95
96pub trait TransmuteInto<T> {
98 fn transmute_into(self) -> T;
100}
101
102pub trait LoadInto {
104 fn load_into(&mut self, memory: &[u8], address: usize) -> Result<(), TrapCode>;
110}
111
112impl<const N: usize> LoadInto for [u8; N] {
113 #[inline]
114 fn load_into(&mut self, memory: &[u8], address: usize) -> Result<(), TrapCode> {
115 let slice: &Self = memory
116 .get(address..)
117 .and_then(|slice| slice.get(..N))
118 .and_then(|slice| slice.try_into().ok())
119 .ok_or(TrapCode::MemoryOutOfBounds)?;
120 *self = *slice;
121 Ok(())
122 }
123}
124
125pub trait StoreFrom {
127 fn store_from(&self, memory: &mut [u8], address: usize) -> Result<(), TrapCode>;
133}
134
135impl<const N: usize> StoreFrom for [u8; N] {
136 #[inline]
137 fn store_from(&self, memory: &mut [u8], address: usize) -> Result<(), TrapCode> {
138 let slice: &mut Self = memory
139 .get_mut(address..)
140 .and_then(|slice| slice.get_mut(..N))
141 .and_then(|slice| slice.try_into().ok())
142 .ok_or(TrapCode::MemoryOutOfBounds)?;
143 *slice = *self;
144 Ok(())
145 }
146}
147
148pub trait LittleEndianConvert {
150 type Bytes: Default + LoadInto + StoreFrom;
152
153 fn into_le_bytes(self) -> Self::Bytes;
155
156 fn from_le_bytes(bytes: Self::Bytes) -> Self;
158}
159
160macro_rules! impl_little_endian_convert_primitive {
161 ( $($primitive:ty),* $(,)? ) => {
162 $(
163 impl LittleEndianConvert for $primitive {
164 type Bytes = [::core::primitive::u8; ::core::mem::size_of::<$primitive>()];
165
166 #[inline]
167 fn into_le_bytes(self) -> Self::Bytes {
168 <$primitive>::to_le_bytes(self)
169 }
170
171 #[inline]
172 fn from_le_bytes(bytes: Self::Bytes) -> Self {
173 <$primitive>::from_le_bytes(bytes)
174 }
175 }
176 )*
177 };
178}
179impl_little_endian_convert_primitive!(u8, u16, u32, u64, i8, i16, i32, i64, f32, f64);
180
181macro_rules! impl_little_endian_convert_float {
182 ( $( struct $float_ty:ident($uint_ty:ty); )* $(,)? ) => {
183 $(
184 impl LittleEndianConvert for $float_ty {
185 type Bytes = <$uint_ty as LittleEndianConvert>::Bytes;
186
187 #[inline]
188 fn into_le_bytes(self) -> Self::Bytes {
189 <$uint_ty>::into_le_bytes(self.to_bits())
190 }
191
192 #[inline]
193 fn from_le_bytes(bytes: Self::Bytes) -> Self {
194 Self::from_bits(<$uint_ty>::from_le_bytes(bytes))
195 }
196 }
197 )*
198 };
199}
200impl_little_endian_convert_float!(
201 struct F32(u32);
202 struct F64(u64);
203);
204
205pub trait ArithmeticOps<T>: Copy {
207 fn add(self, other: T) -> T;
209 fn sub(self, other: T) -> T;
211 fn mul(self, other: T) -> T;
213}
214
215pub trait Integer<T>: ArithmeticOps<T> {
217 fn leading_zeros(self) -> T;
219 fn trailing_zeros(self) -> T;
221 fn count_ones(self) -> T;
223 fn rotl(self, other: T) -> T;
225 fn rotr(self, other: T) -> T;
227 fn div(self, other: T) -> Result<T, TrapCode>;
233 fn rem(self, other: T) -> Result<T, TrapCode>;
239}
240
241pub trait Float<T>: ArithmeticOps<T> {
243 fn abs(self) -> T;
245 fn floor(self) -> T;
247 fn ceil(self) -> T;
249 fn trunc(self) -> T;
251 fn round(self) -> T;
253 fn nearest(self) -> T;
255 fn sqrt(self) -> T;
257 fn is_sign_positive(self) -> bool;
259 fn is_sign_negative(self) -> bool;
261 fn div(self, other: T) -> T;
263 fn min(self, other: T) -> T;
265 fn max(self, other: T) -> T;
267 fn copysign(self, other: T) -> T;
269}
270
271macro_rules! impl_wrap_into {
272 ($from:ident, $into:ident) => {
273 impl WrapInto<$into> for $from {
274 #[inline]
275 fn wrap_into(self) -> $into {
276 self as $into
277 }
278 }
279 };
280 ($from:ident, $intermediate:ident, $into:ident) => {
281 impl WrapInto<$into> for $from {
282 #[inline]
283 fn wrap_into(self) -> $into {
284 $into::from(self as $intermediate)
285 }
286 }
287 };
288}
289
290impl_wrap_into!(i32, i8);
291impl_wrap_into!(i32, i16);
292impl_wrap_into!(i64, i8);
293impl_wrap_into!(i64, i16);
294impl_wrap_into!(i64, i32);
295impl_wrap_into!(i64, f32, F32);
296impl_wrap_into!(u64, f32, F32);
297
298impl_wrap_into!(i32, i32);
300impl_wrap_into!(i64, i64);
301impl_wrap_into!(F32, F32);
302impl_wrap_into!(F64, F64);
303
304impl WrapInto<F32> for F64 {
305 #[inline]
306 fn wrap_into(self) -> F32 {
307 (f64::from(self) as f32).into()
308 }
309}
310
311macro_rules! impl_try_truncate_into {
312 (@primitive $from: ident, $into: ident, $to_primitive:path, $rmin:literal, $rmax:literal) => {
313 impl TryTruncateInto<$into, TrapCode> for $from {
314 #[inline]
315 fn try_truncate_into(self) -> Result<$into, TrapCode> {
316 if self.is_nan() {
317 return Err(TrapCode::BadConversionToInteger);
318 }
319 if self <= $rmin || self >= $rmax {
320 return Err(TrapCode::IntegerOverflow);
321 }
322 Ok(self as _)
323 }
324 }
325
326 impl TruncateSaturateInto<$into> for $from {
327 #[inline]
328 fn truncate_saturate_into(self) -> $into {
329 if self.is_nan() {
330 return <$into as Default>::default();
331 }
332 if self.is_infinite() && self.is_sign_positive() {
333 return <$into>::MAX;
334 }
335 if self.is_infinite() && self.is_sign_negative() {
336 return <$into>::MIN;
337 }
338 self as _
339 }
340 }
341 };
342 (@wrapped $from:ident, $intermediate:ident, $into:ident) => {
343 impl TryTruncateInto<$into, TrapCode> for $from {
344 #[inline]
345 fn try_truncate_into(self) -> Result<$into, TrapCode> {
346 $intermediate::from(self).try_truncate_into()
347 }
348 }
349
350 impl TruncateSaturateInto<$into> for $from {
351 #[inline]
352 fn truncate_saturate_into(self) -> $into {
353 $intermediate::from(self).truncate_saturate_into()
354 }
355 }
356 };
357}
358
359impl_try_truncate_into!(@primitive f32, i32, num_traits::cast::ToPrimitive::to_i32, -2147483904.0_f32, 2147483648.0_f32);
360impl_try_truncate_into!(@primitive f32, u32, num_traits::cast::ToPrimitive::to_u32, -1.0_f32, 4294967296.0_f32);
361impl_try_truncate_into!(@primitive f64, i32, num_traits::cast::ToPrimitive::to_i32, -2147483649.0_f64, 2147483648.0_f64);
362impl_try_truncate_into!(@primitive f64, u32, num_traits::cast::ToPrimitive::to_u32, -1.0_f64, 4294967296.0_f64);
363impl_try_truncate_into!(@primitive f32, i64, num_traits::cast::ToPrimitive::to_i64, -9223373136366403584.0_f32, 9223372036854775808.0_f32);
364impl_try_truncate_into!(@primitive f32, u64, num_traits::cast::ToPrimitive::to_u64, -1.0_f32, 18446744073709551616.0_f32);
365impl_try_truncate_into!(@primitive f64, i64, num_traits::cast::ToPrimitive::to_i64, -9223372036854777856.0_f64, 9223372036854775808.0_f64);
366impl_try_truncate_into!(@primitive f64, u64, num_traits::cast::ToPrimitive::to_u64, -1.0_f64, 18446744073709551616.0_f64);
367impl_try_truncate_into!(@wrapped F32, f32, i32);
368impl_try_truncate_into!(@wrapped F32, f32, i64);
369impl_try_truncate_into!(@wrapped F64, f64, i32);
370impl_try_truncate_into!(@wrapped F64, f64, i64);
371impl_try_truncate_into!(@wrapped F32, f32, u32);
372impl_try_truncate_into!(@wrapped F32, f32, u64);
373impl_try_truncate_into!(@wrapped F64, f64, u32);
374impl_try_truncate_into!(@wrapped F64, f64, u64);
375
376macro_rules! impl_extend_into {
377 ($from:ident, $into:ident) => {
378 impl ExtendInto<$into> for $from {
379 #[inline]
380 fn extend_into(self) -> $into {
381 self as $into
382 }
383 }
384 };
385 ($from:ident, $intermediate:ident, $into:ident) => {
386 impl ExtendInto<$into> for $from {
387 #[inline]
388 fn extend_into(self) -> $into {
389 $into::from(self as $intermediate)
390 }
391 }
392 };
393}
394
395impl_extend_into!(i8, i32);
396impl_extend_into!(u8, i32);
397impl_extend_into!(i16, i32);
398impl_extend_into!(u16, i32);
399impl_extend_into!(i8, i64);
400impl_extend_into!(u8, i64);
401impl_extend_into!(i16, i64);
402impl_extend_into!(u16, i64);
403impl_extend_into!(i32, i64);
404impl_extend_into!(u32, i64);
405impl_extend_into!(u32, u64);
406
407impl_extend_into!(i32, f32, F32);
408impl_extend_into!(i32, f64, F64);
409impl_extend_into!(u32, f32, F32);
410impl_extend_into!(u32, f64, F64);
411impl_extend_into!(i64, f64, F64);
412impl_extend_into!(u64, f64, F64);
413impl_extend_into!(f32, f64, F64);
414
415impl_extend_into!(i32, i32);
417impl_extend_into!(i64, i64);
418impl_extend_into!(F32, F32);
419impl_extend_into!(F64, F64);
420
421impl ExtendInto<F64> for F32 {
422 #[inline]
423 fn extend_into(self) -> F64 {
424 F64::from(f64::from(f32::from(self)))
425 }
426}
427
428macro_rules! impl_sign_extend_from {
429 ( $( impl SignExtendFrom<$from_type:ty> for $for_type:ty; )* ) => {
430 $(
431 impl SignExtendFrom<$from_type> for $for_type {
432 #[inline]
433 fn sign_extend_from(self) -> Self {
434 (self as $from_type) as Self
435 }
436 }
437 )*
438 };
439}
440impl_sign_extend_from! {
441 impl SignExtendFrom<i8> for i32;
442 impl SignExtendFrom<i16> for i32;
443 impl SignExtendFrom<i8> for i64;
444 impl SignExtendFrom<i16> for i64;
445 impl SignExtendFrom<i32> for i64;
446}
447
448macro_rules! impl_transmute_into_self {
449 ($type: ident) => {
450 impl TransmuteInto<$type> for $type {
451 #[inline]
452 fn transmute_into(self) -> $type {
453 self
454 }
455 }
456 };
457}
458
459impl_transmute_into_self!(i32);
460impl_transmute_into_self!(i64);
461impl_transmute_into_self!(f32);
462impl_transmute_into_self!(f64);
463impl_transmute_into_self!(F32);
464impl_transmute_into_self!(F64);
465
466macro_rules! impl_transmute_into_as {
467 ($from: ident, $into: ident) => {
468 impl TransmuteInto<$into> for $from {
469 #[inline]
470 fn transmute_into(self) -> $into {
471 self as $into
472 }
473 }
474 };
475}
476
477impl_transmute_into_as!(i8, u8);
478impl_transmute_into_as!(i32, u32);
479impl_transmute_into_as!(i64, u64);
480
481macro_rules! impl_transmute_into_npf {
482 ($npf:ident, $float:ident, $signed:ident, $unsigned:ident) => {
483 impl TransmuteInto<$float> for $npf {
484 #[inline]
485 fn transmute_into(self) -> $float {
486 self.into()
487 }
488 }
489
490 impl TransmuteInto<$npf> for $float {
491 #[inline]
492 fn transmute_into(self) -> $npf {
493 self.into()
494 }
495 }
496
497 impl TransmuteInto<$signed> for $npf {
498 #[inline]
499 fn transmute_into(self) -> $signed {
500 self.to_bits() as _
501 }
502 }
503
504 impl TransmuteInto<$unsigned> for $npf {
505 #[inline]
506 fn transmute_into(self) -> $unsigned {
507 self.to_bits()
508 }
509 }
510
511 impl TransmuteInto<$npf> for $signed {
512 #[inline]
513 fn transmute_into(self) -> $npf {
514 $npf::from_bits(self as _)
515 }
516 }
517
518 impl TransmuteInto<$npf> for $unsigned {
519 #[inline]
520 fn transmute_into(self) -> $npf {
521 $npf::from_bits(self)
522 }
523 }
524 };
525}
526
527impl_transmute_into_npf!(F32, f32, i32, u32);
528impl_transmute_into_npf!(F64, f64, i64, u64);
529
530impl TransmuteInto<i32> for f32 {
531 #[inline]
532 fn transmute_into(self) -> i32 {
533 self.to_bits() as i32
534 }
535}
536
537impl TransmuteInto<i64> for f64 {
538 #[inline]
539 fn transmute_into(self) -> i64 {
540 self.to_bits() as i64
541 }
542}
543
544impl TransmuteInto<f32> for i32 {
545 #[inline]
546 fn transmute_into(self) -> f32 {
547 f32::from_bits(self as u32)
548 }
549}
550
551impl TransmuteInto<f64> for i64 {
552 #[inline]
553 fn transmute_into(self) -> f64 {
554 f64::from_bits(self as u64)
555 }
556}
557
558impl TransmuteInto<i32> for u32 {
559 #[inline]
560 fn transmute_into(self) -> i32 {
561 self as _
562 }
563}
564
565impl TransmuteInto<i64> for u64 {
566 #[inline]
567 fn transmute_into(self) -> i64 {
568 self as _
569 }
570}
571
572macro_rules! impl_integer_arithmetic_ops {
573 ($type: ident) => {
574 impl ArithmeticOps<$type> for $type {
575 #[inline]
576 fn add(self, other: $type) -> $type {
577 self.wrapping_add(other)
578 }
579 #[inline]
580 fn sub(self, other: $type) -> $type {
581 self.wrapping_sub(other)
582 }
583 #[inline]
584 fn mul(self, other: $type) -> $type {
585 self.wrapping_mul(other)
586 }
587 }
588 };
589}
590
591impl_integer_arithmetic_ops!(i32);
592impl_integer_arithmetic_ops!(u32);
593impl_integer_arithmetic_ops!(i64);
594impl_integer_arithmetic_ops!(u64);
595
596macro_rules! impl_float_arithmetic_ops {
597 ($type:ty) => {
598 impl ArithmeticOps<Self> for $type {
599 #[inline]
600 fn add(self, other: Self) -> Self {
601 self + other
602 }
603 #[inline]
604 fn sub(self, other: Self) -> Self {
605 self - other
606 }
607 #[inline]
608 fn mul(self, other: Self) -> Self {
609 self * other
610 }
611 }
612 };
613}
614
615impl_float_arithmetic_ops!(f32);
616impl_float_arithmetic_ops!(f64);
617impl_float_arithmetic_ops!(F32);
618impl_float_arithmetic_ops!(F64);
619
620macro_rules! impl_integer {
621 ($type:ty) => {
622 impl Integer<Self> for $type {
623 #[inline]
624 fn leading_zeros(self) -> Self {
625 self.leading_zeros() as _
626 }
627 #[inline]
628 fn trailing_zeros(self) -> Self {
629 self.trailing_zeros() as _
630 }
631 #[inline]
632 fn count_ones(self) -> Self {
633 self.count_ones() as _
634 }
635 #[inline]
636 fn rotl(self, other: Self) -> Self {
637 self.rotate_left(other as u32)
638 }
639 #[inline]
640 fn rotr(self, other: Self) -> Self {
641 self.rotate_right(other as u32)
642 }
643 #[inline]
644 fn div(self, other: Self) -> Result<Self, TrapCode> {
645 if other == 0 {
646 return Err(TrapCode::IntegerDivisionByZero);
647 }
648 match self.overflowing_div(other) {
649 (result, false) => Ok(result),
650 _ => Err(TrapCode::IntegerOverflow),
651 }
652 }
653 #[inline]
654 fn rem(self, other: Self) -> Result<Self, TrapCode> {
655 if other == 0 {
656 return Err(TrapCode::IntegerDivisionByZero);
657 }
658 Ok(self.wrapping_rem(other))
659 }
660 }
661 };
662}
663
664impl_integer!(i32);
665impl_integer!(u32);
666impl_integer!(i64);
667impl_integer!(u64);
668
669#[cfg(feature = "std")]
670mod fmath {
671 pub use f32;
672 pub use f64;
673}
674
675#[cfg(not(feature = "std"))]
676mod fmath {
677 pub use super::libm_adapters::{f32, f64};
678}
679
680macro_rules! impl_float {
684 ($type:ident, $fXX:ident, $iXX:ident) => {
685 impl Float<Self> for $type {
687 #[inline]
688 fn abs(self) -> Self {
689 fmath::$fXX::abs(<$fXX>::from(self)).into()
690 }
691 #[inline]
692 fn floor(self) -> Self {
693 fmath::$fXX::floor(<$fXX>::from(self)).into()
694 }
695 #[inline]
696 fn ceil(self) -> Self {
697 fmath::$fXX::ceil(<$fXX>::from(self)).into()
698 }
699 #[inline]
700 fn trunc(self) -> Self {
701 fmath::$fXX::trunc(<$fXX>::from(self)).into()
702 }
703 #[inline]
704 fn round(self) -> Self {
705 fmath::$fXX::round(<$fXX>::from(self)).into()
706 }
707 #[inline]
708 fn nearest(self) -> Self {
709 let round = self.round();
710 if fmath::$fXX::fract(<$fXX>::from(self)).abs() != 0.5 {
711 return round;
712 }
713 let rem = ::core::ops::Rem::rem(round, 2.0);
714 if rem == 1.0 {
715 self.floor()
716 } else if rem == -1.0 {
717 self.ceil()
718 } else {
719 round
720 }
721 }
722 #[inline]
723 fn sqrt(self) -> Self {
724 fmath::$fXX::sqrt(<$fXX>::from(self)).into()
725 }
726 #[inline]
727 fn is_sign_positive(self) -> bool {
728 <$fXX>::is_sign_positive(<$fXX>::from(self)).into()
729 }
730 #[inline]
731 fn is_sign_negative(self) -> bool {
732 <$fXX>::is_sign_negative(<$fXX>::from(self)).into()
733 }
734 #[inline]
735 fn div(self, other: Self) -> Self {
736 self / other
737 }
738 #[inline]
739 fn min(self, other: Self) -> Self {
740 match (self.is_nan(), other.is_nan()) {
743 (true, false) => self,
744 (false, true) => other,
745 _ => {
746 if other.is_sign_negative() {
748 return other.min(self);
749 }
750 self.min(other)
751 }
752 }
753 }
754 #[inline]
755 fn max(self, other: Self) -> Self {
756 match (self.is_nan(), other.is_nan()) {
759 (true, false) => self,
760 (false, true) => other,
761 _ => {
762 if other.is_sign_positive() {
764 return other.max(self);
765 }
766 self.max(other)
767 }
768 }
769 }
770 #[inline]
771 fn copysign(self, other: Self) -> Self {
772 use core::mem::size_of;
773 let sign_mask: $iXX = 1 << ((size_of::<$iXX>() << 3) - 1);
774 let self_int: $iXX = self.transmute_into();
775 let other_int: $iXX = other.transmute_into();
776 let is_self_sign_set = (self_int & sign_mask) != 0;
777 let is_other_sign_set = (other_int & sign_mask) != 0;
778 if is_self_sign_set == is_other_sign_set {
779 self
780 } else if is_other_sign_set {
781 (self_int | sign_mask).transmute_into()
782 } else {
783 (self_int & !sign_mask).transmute_into()
784 }
785 }
786 }
787 };
788}
789
790#[test]
791fn wasm_float_min_regression_works() {
792 assert_eq!(
793 Float::min(F32::from(-0.0), F32::from(0.0)).to_bits(),
794 0x8000_0000,
795 );
796 assert_eq!(
797 Float::min(F32::from(0.0), F32::from(-0.0)).to_bits(),
798 0x8000_0000,
799 );
800}
801
802#[test]
803fn wasm_float_max_regression_works() {
804 assert_eq!(
805 Float::max(F32::from(-0.0), F32::from(0.0)).to_bits(),
806 0x0000_0000,
807 );
808 assert_eq!(
809 Float::max(F32::from(0.0), F32::from(-0.0)).to_bits(),
810 0x0000_0000,
811 );
812}
813
814impl_float!(f32, f32, i32);
815impl_float!(f64, f64, i64);
816impl_float!(F32, f32, i32);
817impl_float!(F64, f64, i64);
818
819#[test]
820fn copysign_regression_works() {
821 use Float as _;
823 assert!(F32::from_bits(0xFFC00000).is_nan());
824 assert_eq!(
825 F32::from_bits(0xFFC00000)
826 .copysign(F32::from_bits(0x0000_0000))
827 .to_bits(),
828 F32::from_bits(0x7FC00000).to_bits()
829 )
830}
831
832#[cfg(not(feature = "std"))]
833mod libm_adapters {
834 pub mod f32 {
835 #[inline]
836 pub fn abs(v: f32) -> f32 {
837 libm::fabsf(v)
838 }
839
840 #[inline]
841 pub fn floor(v: f32) -> f32 {
842 libm::floorf(v)
843 }
844
845 #[inline]
846 pub fn ceil(v: f32) -> f32 {
847 libm::ceilf(v)
848 }
849
850 #[inline]
851 pub fn trunc(v: f32) -> f32 {
852 libm::truncf(v)
853 }
854
855 #[inline]
856 pub fn round(v: f32) -> f32 {
857 libm::roundf(v)
858 }
859
860 #[inline]
861 pub fn fract(v: f32) -> f32 {
862 v - trunc(v)
863 }
864
865 #[inline]
866 pub fn sqrt(v: f32) -> f32 {
867 libm::sqrtf(v)
868 }
869 }
870
871 pub mod f64 {
872 #[inline]
873 pub fn abs(v: f64) -> f64 {
874 libm::fabs(v)
875 }
876
877 #[inline]
878 pub fn floor(v: f64) -> f64 {
879 libm::floor(v)
880 }
881
882 #[inline]
883 pub fn ceil(v: f64) -> f64 {
884 libm::ceil(v)
885 }
886
887 #[inline]
888 pub fn trunc(v: f64) -> f64 {
889 libm::trunc(v)
890 }
891
892 #[inline]
893 pub fn round(v: f64) -> f64 {
894 libm::round(v)
895 }
896
897 #[inline]
898 pub fn fract(v: f64) -> f64 {
899 v - trunc(v)
900 }
901
902 #[inline]
903 pub fn sqrt(v: f64) -> f64 {
904 libm::sqrt(v)
905 }
906 }
907}