gwasmi_core/
value.rs

1use crate::{
2    nan_preserving_float::{F32, F64},
3    TrapCode,
4};
5use core::{f32, i32, i64, u32, u64};
6
7/// Type of a value.
8///
9/// See [`Value`] for details.
10///
11/// [`Value`]: enum.Value.html
12#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
13pub enum ValueType {
14    /// 32-bit signed or unsigned integer.
15    I32,
16    /// 64-bit signed or unsigned integer.
17    I64,
18    /// 32-bit IEEE 754-2008 floating point number.
19    F32,
20    /// 64-bit IEEE 754-2008 floating point number.
21    F64,
22    /// A nullable function reference.
23    FuncRef,
24    /// A nullable external reference.
25    ExternRef,
26}
27
28impl ValueType {
29    /// Returns `true` if [`ValueType`] is a Wasm numeric type.
30    ///
31    /// This is `true` for [`ValueType::I32`], [`ValueType::I64`],
32    /// [`ValueType::F32`] and [`ValueType::F64`].
33    pub fn is_num(&self) -> bool {
34        matches!(self, Self::I32 | Self::I64 | Self::F32 | Self::F64)
35    }
36
37    /// Returns `true` if [`ValueType`] is a Wasm reference type.
38    ///
39    /// This is `true` for [`ValueType::FuncRef`] and [`ValueType::ExternRef`].
40    pub fn is_ref(&self) -> bool {
41        matches!(self, Self::ExternRef | Self::FuncRef)
42    }
43}
44
45/// Convert one type to another by wrapping.
46pub trait WrapInto<T> {
47    /// Convert one type to another by wrapping.
48    fn wrap_into(self) -> T;
49}
50
51/// Convert one type to another by rounding to the nearest integer towards zero.
52///
53/// # Errors
54///
55/// Traps when the input float cannot be represented by the target integer or
56/// when the input float is NaN.
57pub trait TryTruncateInto<T, E> {
58    /// Convert one type to another by rounding to the nearest integer towards zero.
59    ///
60    /// # Errors
61    ///
62    /// - If the input float value is NaN (not a number).
63    /// - If the input float value cannot be represented using the truncated
64    ///   integer type.
65    fn try_truncate_into(self) -> Result<T, E>;
66}
67
68/// Convert one type to another by rounding to the nearest integer towards zero.
69///
70/// # Note
71///
72/// This has saturating semantics for when the integer cannot represent the float.
73///
74/// Returns
75///
76/// - `0` when the input is NaN.
77/// - `int::MIN` when the input is -INF.
78/// - `int::MAX` when the input is +INF.
79pub trait TruncateSaturateInto<T> {
80    /// Convert one type to another by rounding to the nearest integer towards zero.
81    fn truncate_saturate_into(self) -> T;
82}
83
84/// Convert one type to another by extending with leading zeroes.
85pub trait ExtendInto<T> {
86    /// Convert one type to another by extending with leading zeroes.
87    fn extend_into(self) -> T;
88}
89
90/// Sign-extends `Self` integer type from `T` integer type.
91pub trait SignExtendFrom<T> {
92    /// Convert one type to another by extending with leading zeroes.
93    fn sign_extend_from(self) -> Self;
94}
95
96/// Reinterprets the bits of a value of one type as another type.
97pub trait TransmuteInto<T> {
98    /// Reinterprets the bits of a value of one type as another type.
99    fn transmute_into(self) -> T;
100}
101
102/// Allows to efficiently load bytes from `memory` into a buffer.
103pub trait LoadInto {
104    /// Loads bytes from `memory` into `self`.
105    ///
106    /// # Errors
107    ///
108    /// Traps if the `memory` access is out of bounds.
109    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
125/// Allows to efficiently write bytes from a buffer into `memory`.
126pub trait StoreFrom {
127    /// Writes bytes from `self` to `memory`.
128    ///
129    /// # Errors
130    ///
131    /// Traps if the `memory` access is out of bounds.
132    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
148/// Types that can be converted from and to little endian bytes.
149pub trait LittleEndianConvert {
150    /// The little endian bytes representation.
151    type Bytes: Default + LoadInto + StoreFrom;
152
153    /// Converts `self` into little endian bytes.
154    fn into_le_bytes(self) -> Self::Bytes;
155
156    /// Converts little endian bytes into `Self`.
157    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
205/// Arithmetic operations.
206pub trait ArithmeticOps<T>: Copy {
207    /// Add two values.
208    fn add(self, other: T) -> T;
209    /// Subtract two values.
210    fn sub(self, other: T) -> T;
211    /// Multiply two values.
212    fn mul(self, other: T) -> T;
213}
214
215/// Integer value.
216pub trait Integer<T>: ArithmeticOps<T> {
217    /// Counts leading zeros in the bitwise representation of the value.
218    fn leading_zeros(self) -> T;
219    /// Counts trailing zeros in the bitwise representation of the value.
220    fn trailing_zeros(self) -> T;
221    /// Counts 1-bits in the bitwise representation of the value.
222    fn count_ones(self) -> T;
223    /// Get left bit rotation result.
224    fn rotl(self, other: T) -> T;
225    /// Get right bit rotation result.
226    fn rotr(self, other: T) -> T;
227    /// Divide two values.
228    ///
229    /// # Errors
230    ///
231    /// If `other` is equal to zero.
232    fn div(self, other: T) -> Result<T, TrapCode>;
233    /// Get division remainder.
234    ///
235    /// # Errors
236    ///
237    /// If `other` is equal to zero.
238    fn rem(self, other: T) -> Result<T, TrapCode>;
239}
240
241/// Float-point value.
242pub trait Float<T>: ArithmeticOps<T> {
243    /// Get absolute value.
244    fn abs(self) -> T;
245    /// Returns the largest integer less than or equal to a number.
246    fn floor(self) -> T;
247    /// Returns the smallest integer greater than or equal to a number.
248    fn ceil(self) -> T;
249    /// Returns the integer part of a number.
250    fn trunc(self) -> T;
251    /// Returns the nearest integer to a number. Round half-way cases away from 0.0.
252    fn round(self) -> T;
253    /// Returns the nearest integer to a number. Ties are round to even number.
254    fn nearest(self) -> T;
255    /// Takes the square root of a number.
256    fn sqrt(self) -> T;
257    /// Returns `true` if the sign of the number is positive.
258    fn is_sign_positive(self) -> bool;
259    /// Returns `true` if the sign of the number is negative.
260    fn is_sign_negative(self) -> bool;
261    /// Returns the division of the two numbers.
262    fn div(self, other: T) -> T;
263    /// Returns the minimum of the two numbers.
264    fn min(self, other: T) -> T;
265    /// Returns the maximum of the two numbers.
266    fn max(self, other: T) -> T;
267    /// Sets sign of this value to the sign of other value.
268    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
298// Casting to self
299impl_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
415// Casting to self
416impl_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
680// We cannot call the math functions directly, because they are not all available in `core`.
681// In no-std cases we instead rely on `libm`.
682// These wrappers handle that delegation.
683macro_rules! impl_float {
684    ($type:ident, $fXX:ident, $iXX:ident) => {
685        // In this particular instance we want to directly compare floating point numbers.
686        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                // The implementation strictly adheres to the mandated behavior for the Wasm specification.
741                // Note: In other contexts this API is also known as: `nan_min`.
742                match (self.is_nan(), other.is_nan()) {
743                    (true, false) => self,
744                    (false, true) => other,
745                    _ => {
746                        // Case: Both values are NaN; OR both values are non-NaN.
747                        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                // The implementation strictly adheres to the mandated behavior for the Wasm specification.
757                // Note: In other contexts this API is also known as: `nan_max`.
758                match (self.is_nan(), other.is_nan()) {
759                    (true, false) => self,
760                    (false, true) => other,
761                    _ => {
762                        // Case: Both values are NaN; OR both values are non-NaN.
763                        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    // This test has been directly extracted from a WebAssembly Specification assertion.
822    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}