1use crate::{
2 nan_preserving_float::{F32, F64},
3 TrapCode,
4};
5use core::{f32, fmt, fmt::Display};
6
7#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
13pub enum ValueType {
14 I32,
16 I64,
18 F32,
20 F64,
22}
23
24impl Display for ValueType {
25 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
26 match self {
27 Self::I32 => write!(f, "i32"),
28 Self::I64 => write!(f, "i64"),
29 Self::F32 => write!(f, "f32"),
30 Self::F64 => write!(f, "f64"),
31 }
32 }
33}
34
35#[derive(Copy, Clone, Debug, PartialEq)]
43pub enum Value {
44 I32(i32),
46 I64(i64),
48 F32(F32),
50 F64(F64),
52}
53
54impl Display for Value {
55 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
56 match self {
57 Self::I32(value) => write!(f, "{value}"),
58 Self::I64(value) => write!(f, "{value}"),
59 Self::F32(value) => write!(f, "{}", f32::from(*value)),
60 Self::F64(value) => write!(f, "{}", f64::from(*value)),
61 }
62 }
63}
64
65pub trait FromValue
75where
76 Self: Sized,
77{
78 fn from_value(val: Value) -> Option<Self>;
85}
86
87pub trait WrapInto<T> {
89 fn wrap_into(self) -> T;
91}
92
93pub trait TryTruncateInto<T, E> {
100 fn try_truncate_into(self) -> Result<T, E>;
102}
103
104pub trait TruncateSaturateInto<T> {
116 fn truncate_saturate_into(self) -> T;
118}
119
120pub trait ExtendInto<T> {
122 fn extend_into(self) -> T;
124}
125
126pub trait SignExtendFrom<T> {
128 fn sign_extend_from(self) -> Self;
130}
131
132pub trait TransmuteInto<T> {
134 fn transmute_into(self) -> T;
136}
137
138pub trait LittleEndianConvert {
140 type Bytes: Default + AsRef<[u8]> + AsMut<[u8]>;
142
143 fn into_le_bytes(self) -> Self::Bytes;
145
146 fn from_le_bytes(bytes: Self::Bytes) -> Self;
148}
149
150macro_rules! impl_little_endian_convert_primitive {
151 ( $($primitive:ty),* $(,)? ) => {
152 $(
153 impl LittleEndianConvert for $primitive {
154 type Bytes = [::core::primitive::u8; ::core::mem::size_of::<$primitive>()];
155
156 #[inline]
157 fn into_le_bytes(self) -> Self::Bytes {
158 <$primitive>::to_le_bytes(self)
159 }
160
161 #[inline]
162 fn from_le_bytes(bytes: Self::Bytes) -> Self {
163 <$primitive>::from_le_bytes(bytes)
164 }
165 }
166 )*
167 };
168}
169impl_little_endian_convert_primitive!(u8, u16, u32, u64, i8, i16, i32, i64, f32, f64);
170
171macro_rules! impl_little_endian_convert_float {
172 ( $( struct $float_ty:ident($uint_ty:ty); )* $(,)? ) => {
173 $(
174 impl LittleEndianConvert for $float_ty {
175 type Bytes = <$uint_ty as LittleEndianConvert>::Bytes;
176
177 #[inline]
178 fn into_le_bytes(self) -> Self::Bytes {
179 <$uint_ty>::into_le_bytes(self.to_bits())
180 }
181
182 #[inline]
183 fn from_le_bytes(bytes: Self::Bytes) -> Self {
184 Self::from_bits(<$uint_ty>::from_le_bytes(bytes))
185 }
186 }
187 )*
188 };
189}
190impl_little_endian_convert_float!(
191 struct F32(u32);
192 struct F64(u64);
193);
194
195pub trait ArithmeticOps<T>: Copy {
197 fn add(self, other: T) -> T;
199 fn sub(self, other: T) -> T;
201 fn mul(self, other: T) -> T;
203 fn div(self, other: T) -> Result<T, TrapCode>;
205}
206
207pub trait Integer<T>: ArithmeticOps<T> {
209 fn leading_zeros(self) -> T;
211 fn trailing_zeros(self) -> T;
213 fn count_ones(self) -> T;
215 fn rotl(self, other: T) -> T;
217 fn rotr(self, other: T) -> T;
219 fn rem(self, other: T) -> Result<T, TrapCode>;
221}
222
223pub trait Float<T>: ArithmeticOps<T> {
225 fn abs(self) -> T;
227 fn floor(self) -> T;
229 fn ceil(self) -> T;
231 fn trunc(self) -> T;
233 fn round(self) -> T;
235 fn nearest(self) -> T;
237 fn sqrt(self) -> T;
239 fn is_sign_positive(self) -> bool;
241 fn is_sign_negative(self) -> bool;
243 fn min(self, other: T) -> T;
245 fn max(self, other: T) -> T;
247 fn copysign(self, other: T) -> T;
249}
250
251impl Value {
252 #[inline]
254 pub fn default(value_type: ValueType) -> Self {
255 match value_type {
256 ValueType::I32 => Value::I32(0),
257 ValueType::I64 => Value::I64(0),
258 ValueType::F32 => Value::F32(0f32.into()),
259 ValueType::F64 => Value::F64(0f64.into()),
260 }
261 }
262
263 #[deprecated(note = "use `F32::from_bits(val).into()` instead")]
265 pub fn decode_f32(val: u32) -> Self {
266 Value::F32(F32::from_bits(val))
267 }
268
269 #[deprecated(note = "use `F64::from_bits(val).into()` instead")]
271 pub fn decode_f64(val: u64) -> Self {
272 Value::F64(F64::from_bits(val))
273 }
274
275 #[inline]
277 pub fn value_type(&self) -> ValueType {
278 match *self {
279 Value::I32(_) => ValueType::I32,
280 Value::I64(_) => ValueType::I64,
281 Value::F32(_) => ValueType::F32,
282 Value::F64(_) => ValueType::F64,
283 }
284 }
285
286 #[inline]
294 pub fn try_into<T: FromValue>(self) -> Option<T> {
295 FromValue::from_value(self)
296 }
297}
298
299impl From<i8> for Value {
300 #[inline]
301 fn from(val: i8) -> Self {
302 Value::I32(val as i32)
303 }
304}
305
306impl From<i16> for Value {
307 #[inline]
308 fn from(val: i16) -> Self {
309 Value::I32(val as i32)
310 }
311}
312
313impl From<i32> for Value {
314 #[inline]
315 fn from(val: i32) -> Self {
316 Value::I32(val)
317 }
318}
319
320impl From<i64> for Value {
321 #[inline]
322 fn from(val: i64) -> Self {
323 Value::I64(val)
324 }
325}
326
327impl From<u8> for Value {
328 #[inline]
329 fn from(val: u8) -> Self {
330 Value::I32(val as i32)
331 }
332}
333
334impl From<u16> for Value {
335 #[inline]
336 fn from(val: u16) -> Self {
337 Value::I32(val as i32)
338 }
339}
340
341impl From<u32> for Value {
342 #[inline]
343 fn from(val: u32) -> Self {
344 Value::I32(val.transmute_into())
345 }
346}
347
348impl From<u64> for Value {
349 #[inline]
350 fn from(val: u64) -> Self {
351 Value::I64(val.transmute_into())
352 }
353}
354
355impl From<F32> for Value {
356 #[inline]
357 fn from(val: F32) -> Self {
358 Value::F32(val)
359 }
360}
361
362impl From<F64> for Value {
363 #[inline]
364 fn from(val: F64) -> Self {
365 Value::F64(val)
366 }
367}
368
369macro_rules! impl_from_value {
370 ($expected_rt_ty: ident, $into: ty) => {
371 impl FromValue for $into {
372 #[inline]
373 fn from_value(val: Value) -> Option<Self> {
374 match val {
375 Value::$expected_rt_ty(val) => Some(val.transmute_into()),
376 _ => None,
377 }
378 }
379 }
380 };
381}
382
383impl FromValue for bool {
388 #[inline]
389 fn from_value(val: Value) -> Option<Self> {
390 match val {
391 Value::I32(val) => Some(val != 0),
392 _ => None,
393 }
394 }
395}
396
397impl FromValue for i8 {
401 #[inline]
402 fn from_value(val: Value) -> Option<Self> {
403 let min = i8::MIN as i32;
404 let max = i8::MAX as i32;
405 match val {
406 Value::I32(val) if min <= val && val <= max => Some(val as i8),
407 _ => None,
408 }
409 }
410}
411
412impl FromValue for i16 {
416 #[inline]
417 fn from_value(val: Value) -> Option<Self> {
418 let min = i16::MIN as i32;
419 let max = i16::MAX as i32;
420 match val {
421 Value::I32(val) if min <= val && val <= max => Some(val as i16),
422 _ => None,
423 }
424 }
425}
426
427impl FromValue for u8 {
431 #[inline]
432 fn from_value(val: Value) -> Option<Self> {
433 let min = u8::MIN as i32;
434 let max = u8::MAX as i32;
435 match val {
436 Value::I32(val) if min <= val && val <= max => Some(val as u8),
437 _ => None,
438 }
439 }
440}
441
442impl FromValue for u16 {
446 #[inline]
447 fn from_value(val: Value) -> Option<Self> {
448 let min = u16::MIN as i32;
449 let max = u16::MAX as i32;
450 match val {
451 Value::I32(val) if min <= val && val <= max => Some(val as u16),
452 _ => None,
453 }
454 }
455}
456
457impl_from_value!(I32, i32);
458impl_from_value!(I64, i64);
459impl_from_value!(F32, F32);
460impl_from_value!(F64, F64);
461impl_from_value!(I32, u32);
462impl_from_value!(I64, u64);
463
464macro_rules! impl_wrap_into {
465 ($from:ident, $into:ident) => {
466 impl WrapInto<$into> for $from {
467 #[inline]
468 fn wrap_into(self) -> $into {
469 self as $into
470 }
471 }
472 };
473 ($from:ident, $intermediate:ident, $into:ident) => {
474 impl WrapInto<$into> for $from {
475 #[inline]
476 fn wrap_into(self) -> $into {
477 $into::from(self as $intermediate)
478 }
479 }
480 };
481}
482
483impl_wrap_into!(i32, i8);
484impl_wrap_into!(i32, i16);
485impl_wrap_into!(i64, i8);
486impl_wrap_into!(i64, i16);
487impl_wrap_into!(i64, i32);
488impl_wrap_into!(i64, f32, F32);
489impl_wrap_into!(u64, f32, F32);
490impl_wrap_into!(f64, f32);
494
495impl WrapInto<F32> for F64 {
496 #[inline]
497 fn wrap_into(self) -> F32 {
498 (f64::from(self) as f32).into()
499 }
500}
501
502macro_rules! impl_try_truncate_into {
503 (@primitive $from: ident, $into: ident, $to_primitive:path) => {
504 impl TryTruncateInto<$into, TrapCode> for $from {
505 #[inline]
506 fn try_truncate_into(self) -> Result<$into, TrapCode> {
507 if self.is_nan() {
509 return Err(TrapCode::InvalidConversionToInt);
510 }
511 num_rational::BigRational::from_float(self)
512 .map(|val| val.to_integer())
513 .and_then(|val| $to_primitive(&val))
514 .ok_or(TrapCode::IntegerOverflow)
515 }
516 }
517
518 impl TruncateSaturateInto<$into> for $from {
519 #[inline]
520 fn truncate_saturate_into(self) -> $into {
521 if self.is_nan() {
522 return <$into as Default>::default();
523 }
524 if self.is_infinite() && self.is_sign_positive() {
525 return <$into>::MAX;
526 }
527 if self.is_infinite() && self.is_sign_negative() {
528 return <$into>::MIN;
529 }
530 self as _
531 }
532 }
533 };
534 (@wrapped $from:ident, $intermediate:ident, $into:ident) => {
535 impl TryTruncateInto<$into, TrapCode> for $from {
536 #[inline]
537 fn try_truncate_into(self) -> Result<$into, TrapCode> {
538 $intermediate::from(self).try_truncate_into()
539 }
540 }
541
542 impl TruncateSaturateInto<$into> for $from {
543 #[inline]
544 fn truncate_saturate_into(self) -> $into {
545 $intermediate::from(self).truncate_saturate_into()
546 }
547 }
548 };
549}
550
551impl_try_truncate_into!(@primitive f32, i32, num_traits::cast::ToPrimitive::to_i32);
552impl_try_truncate_into!(@primitive f32, i64, num_traits::cast::ToPrimitive::to_i64);
553impl_try_truncate_into!(@primitive f64, i32, num_traits::cast::ToPrimitive::to_i32);
554impl_try_truncate_into!(@primitive f64, i64, num_traits::cast::ToPrimitive::to_i64);
555impl_try_truncate_into!(@primitive f32, u32, num_traits::cast::ToPrimitive::to_u32);
556impl_try_truncate_into!(@primitive f32, u64, num_traits::cast::ToPrimitive::to_u64);
557impl_try_truncate_into!(@primitive f64, u32, num_traits::cast::ToPrimitive::to_u32);
558impl_try_truncate_into!(@primitive f64, u64, num_traits::cast::ToPrimitive::to_u64);
559impl_try_truncate_into!(@wrapped F32, f32, i32);
560impl_try_truncate_into!(@wrapped F32, f32, i64);
561impl_try_truncate_into!(@wrapped F64, f64, i32);
562impl_try_truncate_into!(@wrapped F64, f64, i64);
563impl_try_truncate_into!(@wrapped F32, f32, u32);
564impl_try_truncate_into!(@wrapped F32, f32, u64);
565impl_try_truncate_into!(@wrapped F64, f64, u32);
566impl_try_truncate_into!(@wrapped F64, f64, u64);
567
568macro_rules! impl_extend_into {
569 ($from:ident, $into:ident) => {
570 impl ExtendInto<$into> for $from {
571 #[inline]
572 fn extend_into(self) -> $into {
573 self as $into
574 }
575 }
576 };
577 ($from:ident, $intermediate:ident, $into:ident) => {
578 impl ExtendInto<$into> for $from {
579 #[inline]
580 fn extend_into(self) -> $into {
581 $into::from(self as $intermediate)
582 }
583 }
584 };
585}
586
587impl_extend_into!(i8, i32);
588impl_extend_into!(u8, i32);
589impl_extend_into!(i16, i32);
590impl_extend_into!(u16, i32);
591impl_extend_into!(i8, i64);
592impl_extend_into!(u8, i64);
593impl_extend_into!(i16, i64);
594impl_extend_into!(u16, i64);
595impl_extend_into!(i32, i64);
596impl_extend_into!(u32, i64);
597impl_extend_into!(u32, u64);
598impl_extend_into!(i32, f32);
599impl_extend_into!(i32, f64);
600impl_extend_into!(u32, f32);
601impl_extend_into!(u32, f64);
602impl_extend_into!(i64, f64);
603impl_extend_into!(u64, f64);
604impl_extend_into!(f32, f64);
605
606impl_extend_into!(i32, f32, F32);
607impl_extend_into!(i32, f64, F64);
608impl_extend_into!(u32, f32, F32);
609impl_extend_into!(u32, f64, F64);
610impl_extend_into!(i64, f64, F64);
611impl_extend_into!(u64, f64, F64);
612impl_extend_into!(f32, f64, F64);
613
614impl ExtendInto<F64> for F32 {
615 #[inline]
616 fn extend_into(self) -> F64 {
617 (f32::from(self) as f64).into()
618 }
619}
620
621macro_rules! impl_sign_extend_from {
622 ( $( impl SignExtendFrom<$from_type:ty> for $for_type:ty; )* ) => {
623 $(
624 impl SignExtendFrom<$from_type> for $for_type {
625 #[inline]
626 fn sign_extend_from(self) -> Self {
627 (self as $from_type) as Self
628 }
629 }
630 )*
631 };
632}
633impl_sign_extend_from! {
634 impl SignExtendFrom<i8> for i32;
635 impl SignExtendFrom<i16> for i32;
636 impl SignExtendFrom<i8> for i64;
637 impl SignExtendFrom<i16> for i64;
638 impl SignExtendFrom<i32> for i64;
639}
640
641macro_rules! impl_transmute_into_self {
642 ($type: ident) => {
643 impl TransmuteInto<$type> for $type {
644 #[inline]
645 fn transmute_into(self) -> $type {
646 self
647 }
648 }
649 };
650}
651
652impl_transmute_into_self!(i32);
653impl_transmute_into_self!(i64);
654impl_transmute_into_self!(f32);
655impl_transmute_into_self!(f64);
656impl_transmute_into_self!(F32);
657impl_transmute_into_self!(F64);
658
659macro_rules! impl_transmute_into_as {
660 ($from: ident, $into: ident) => {
661 impl TransmuteInto<$into> for $from {
662 #[inline]
663 fn transmute_into(self) -> $into {
664 self as $into
665 }
666 }
667 };
668}
669
670impl_transmute_into_as!(i8, u8);
671impl_transmute_into_as!(i32, u32);
672impl_transmute_into_as!(i64, u64);
673
674macro_rules! impl_transmute_into_npf {
675 ($npf:ident, $float:ident, $signed:ident, $unsigned:ident) => {
676 impl TransmuteInto<$float> for $npf {
677 #[inline]
678 fn transmute_into(self) -> $float {
679 self.into()
680 }
681 }
682
683 impl TransmuteInto<$npf> for $float {
684 #[inline]
685 fn transmute_into(self) -> $npf {
686 self.into()
687 }
688 }
689
690 impl TransmuteInto<$signed> for $npf {
691 #[inline]
692 fn transmute_into(self) -> $signed {
693 self.to_bits() as _
694 }
695 }
696
697 impl TransmuteInto<$unsigned> for $npf {
698 #[inline]
699 fn transmute_into(self) -> $unsigned {
700 self.to_bits()
701 }
702 }
703
704 impl TransmuteInto<$npf> for $signed {
705 #[inline]
706 fn transmute_into(self) -> $npf {
707 $npf::from_bits(self as _)
708 }
709 }
710
711 impl TransmuteInto<$npf> for $unsigned {
712 #[inline]
713 fn transmute_into(self) -> $npf {
714 $npf::from_bits(self)
715 }
716 }
717 };
718}
719
720impl_transmute_into_npf!(F32, f32, i32, u32);
721impl_transmute_into_npf!(F64, f64, i64, u64);
722
723impl TransmuteInto<i32> for f32 {
724 #[inline]
725 fn transmute_into(self) -> i32 {
726 self.to_bits() as i32
727 }
728}
729
730impl TransmuteInto<i64> for f64 {
731 #[inline]
732 fn transmute_into(self) -> i64 {
733 self.to_bits() as i64
734 }
735}
736
737impl TransmuteInto<f32> for i32 {
738 #[inline]
739 fn transmute_into(self) -> f32 {
740 f32::from_bits(self as u32)
741 }
742}
743
744impl TransmuteInto<f64> for i64 {
745 #[inline]
746 fn transmute_into(self) -> f64 {
747 f64::from_bits(self as u64)
748 }
749}
750
751impl TransmuteInto<i32> for u32 {
752 #[inline]
753 fn transmute_into(self) -> i32 {
754 self as _
755 }
756}
757
758impl TransmuteInto<i64> for u64 {
759 #[inline]
760 fn transmute_into(self) -> i64 {
761 self as _
762 }
763}
764
765macro_rules! impl_integer_arithmetic_ops {
766 ($type: ident) => {
767 impl ArithmeticOps<$type> for $type {
768 #[inline]
769 fn add(self, other: $type) -> $type {
770 self.wrapping_add(other)
771 }
772 #[inline]
773 fn sub(self, other: $type) -> $type {
774 self.wrapping_sub(other)
775 }
776 #[inline]
777 fn mul(self, other: $type) -> $type {
778 self.wrapping_mul(other)
779 }
780 #[inline]
781 fn div(self, other: $type) -> Result<$type, TrapCode> {
782 if other == 0 {
783 Err(TrapCode::DivisionByZero)
784 } else {
785 let (result, overflow) = self.overflowing_div(other);
786 if overflow {
787 Err(TrapCode::IntegerOverflow)
788 } else {
789 Ok(result)
790 }
791 }
792 }
793 }
794 };
795}
796
797impl_integer_arithmetic_ops!(i32);
798impl_integer_arithmetic_ops!(u32);
799impl_integer_arithmetic_ops!(i64);
800impl_integer_arithmetic_ops!(u64);
801
802macro_rules! impl_float_arithmetic_ops {
803 ($type: ident) => {
804 impl ArithmeticOps<$type> for $type {
805 #[inline]
806 fn add(self, other: $type) -> $type {
807 self + other
808 }
809 #[inline]
810 fn sub(self, other: $type) -> $type {
811 self - other
812 }
813 #[inline]
814 fn mul(self, other: $type) -> $type {
815 self * other
816 }
817 #[inline]
818 fn div(self, other: $type) -> Result<$type, TrapCode> {
819 Ok(self / other)
820 }
821 }
822 };
823}
824
825impl_float_arithmetic_ops!(f32);
826impl_float_arithmetic_ops!(f64);
827impl_float_arithmetic_ops!(F32);
828impl_float_arithmetic_ops!(F64);
829
830macro_rules! impl_integer {
831 ($type: ident) => {
832 impl Integer<$type> for $type {
833 #[inline]
834 fn leading_zeros(self) -> $type {
835 self.leading_zeros() as $type
836 }
837 #[inline]
838 fn trailing_zeros(self) -> $type {
839 self.trailing_zeros() as $type
840 }
841 #[inline]
842 fn count_ones(self) -> $type {
843 self.count_ones() as $type
844 }
845 #[inline]
846 fn rotl(self, other: $type) -> $type {
847 self.rotate_left(other as u32)
848 }
849 #[inline]
850 fn rotr(self, other: $type) -> $type {
851 self.rotate_right(other as u32)
852 }
853 #[inline]
854 fn rem(self, other: $type) -> Result<$type, TrapCode> {
855 if other == 0 {
856 Err(TrapCode::DivisionByZero)
857 } else {
858 Ok(self.wrapping_rem(other))
859 }
860 }
861 }
862 };
863}
864
865impl_integer!(i32);
866impl_integer!(u32);
867impl_integer!(i64);
868impl_integer!(u64);
869
870#[cfg(feature = "std")]
871mod fmath {
872 pub use f32;
873 pub use f64;
874}
875
876#[cfg(not(feature = "std"))]
877mod fmath {
878 pub use super::libm_adapters::{f32, f64};
879}
880
881macro_rules! impl_float {
885 ($type:ident, $fXX:ident, $iXX:ident) => {
886 impl Float<$type> for $type {
888 #[inline]
889 fn abs(self) -> $type {
890 fmath::$fXX::abs($fXX::from(self)).into()
891 }
892 #[inline]
893 fn floor(self) -> $type {
894 fmath::$fXX::floor($fXX::from(self)).into()
895 }
896 #[inline]
897 fn ceil(self) -> $type {
898 fmath::$fXX::ceil($fXX::from(self)).into()
899 }
900 #[inline]
901 fn trunc(self) -> $type {
902 fmath::$fXX::trunc($fXX::from(self)).into()
903 }
904 #[inline]
905 fn round(self) -> $type {
906 fmath::$fXX::round($fXX::from(self)).into()
907 }
908 #[inline]
909 fn nearest(self) -> $type {
910 let round = self.round();
911 if fmath::$fXX::fract($fXX::from(self)).abs() != 0.5 {
912 return round;
913 }
914
915 use core::ops::Rem;
916 if round.rem(2.0) == 1.0 {
917 self.floor()
918 } else if round.rem(2.0) == -1.0 {
919 self.ceil()
920 } else {
921 round
922 }
923 }
924 #[inline]
925 fn sqrt(self) -> $type {
926 fmath::$fXX::sqrt($fXX::from(self)).into()
927 }
928 #[inline]
929 fn is_sign_positive(self) -> bool {
930 $fXX::is_sign_positive($fXX::from(self)).into()
931 }
932 #[inline]
933 fn is_sign_negative(self) -> bool {
934 $fXX::is_sign_negative($fXX::from(self)).into()
935 }
936 #[inline]
937 fn min(self, other: $type) -> $type {
938 match (self.is_nan(), other.is_nan()) {
941 (true, false) => self,
942 (false, true) => other,
943 _ => {
944 if other.is_sign_negative() {
946 return other.min(self);
947 }
948 self.min(other)
949 }
950 }
951 }
952 #[inline]
953 fn max(self, other: $type) -> $type {
954 match (self.is_nan(), other.is_nan()) {
957 (true, false) => self,
958 (false, true) => other,
959 _ => {
960 if other.is_sign_positive() {
962 return other.max(self);
963 }
964 self.max(other)
965 }
966 }
967 }
968 #[inline]
969 fn copysign(self, other: $type) -> $type {
970 use core::mem::size_of;
971 let sign_mask: $iXX = 1 << ((size_of::<$iXX>() << 3) - 1);
972 let self_int: $iXX = self.transmute_into();
973 let other_int: $iXX = other.transmute_into();
974 let is_self_sign_set = (self_int & sign_mask) != 0;
975 let is_other_sign_set = (other_int & sign_mask) != 0;
976 if is_self_sign_set == is_other_sign_set {
977 self
978 } else if is_other_sign_set {
979 (self_int | sign_mask).transmute_into()
980 } else {
981 (self_int & !sign_mask).transmute_into()
982 }
983 }
984 }
985 };
986}
987
988#[test]
989fn wasm_float_min_regression_works() {
990 assert_eq!(
991 Float::min(F32::from(-0.0), F32::from(0.0)).to_bits(),
992 0x8000_0000,
993 );
994 assert_eq!(
995 Float::min(F32::from(0.0), F32::from(-0.0)).to_bits(),
996 0x8000_0000,
997 );
998}
999
1000#[test]
1001fn wasm_float_max_regression_works() {
1002 assert_eq!(
1003 Float::max(F32::from(-0.0), F32::from(0.0)).to_bits(),
1004 0x0000_0000,
1005 );
1006 assert_eq!(
1007 Float::max(F32::from(0.0), F32::from(-0.0)).to_bits(),
1008 0x0000_0000,
1009 );
1010}
1011
1012impl_float!(f32, f32, i32);
1013impl_float!(f64, f64, i64);
1014impl_float!(F32, f32, i32);
1015impl_float!(F64, f64, i64);
1016
1017#[test]
1018fn copysign_regression_works() {
1019 use Float as _;
1021 assert!(F32::from_bits(0xFFC00000).is_nan());
1022 assert_eq!(
1023 F32::from_bits(0xFFC00000)
1024 .copysign(F32::from_bits(0x0000_0000))
1025 .to_bits(),
1026 F32::from_bits(0x7FC00000).to_bits()
1027 )
1028}
1029
1030#[cfg(not(feature = "std"))]
1031mod libm_adapters {
1032 pub mod f32 {
1033 #[inline]
1034 pub fn abs(v: f32) -> f32 {
1035 libm::fabsf(v)
1036 }
1037
1038 #[inline]
1039 pub fn floor(v: f32) -> f32 {
1040 libm::floorf(v)
1041 }
1042
1043 #[inline]
1044 pub fn ceil(v: f32) -> f32 {
1045 libm::ceilf(v)
1046 }
1047
1048 #[inline]
1049 pub fn trunc(v: f32) -> f32 {
1050 libm::truncf(v)
1051 }
1052
1053 #[inline]
1054 pub fn round(v: f32) -> f32 {
1055 libm::roundf(v)
1056 }
1057
1058 #[inline]
1059 pub fn fract(v: f32) -> f32 {
1060 v - trunc(v)
1061 }
1062
1063 #[inline]
1064 pub fn sqrt(v: f32) -> f32 {
1065 libm::sqrtf(v)
1066 }
1067 }
1068
1069 pub mod f64 {
1070 #[inline]
1071 pub fn abs(v: f64) -> f64 {
1072 libm::fabs(v)
1073 }
1074
1075 #[inline]
1076 pub fn floor(v: f64) -> f64 {
1077 libm::floor(v)
1078 }
1079
1080 #[inline]
1081 pub fn ceil(v: f64) -> f64 {
1082 libm::ceil(v)
1083 }
1084
1085 #[inline]
1086 pub fn trunc(v: f64) -> f64 {
1087 libm::trunc(v)
1088 }
1089
1090 #[inline]
1091 pub fn round(v: f64) -> f64 {
1092 libm::round(v)
1093 }
1094
1095 #[inline]
1096 pub fn fract(v: f64) -> f64 {
1097 v - trunc(v)
1098 }
1099
1100 #[inline]
1101 pub fn sqrt(v: f64) -> f64 {
1102 libm::sqrt(v)
1103 }
1104 }
1105}