| // If `src` can be promoted to `$dst`, then it must be Ok to cast `dst` back to |
| // `$src` |
| macro_rules! promote_and_back { |
| ($($src:ident => $($dst:ident),+);+;) => { |
| mod demoting_to { |
| $( |
| mod $src { |
| mod from { |
| use crate::From; |
| |
| $( |
| quickcheck! { |
| fn $dst(src: $src) -> bool { |
| $src::cast($dst::cast(src)).is_ok() |
| } |
| } |
| )+ |
| } |
| } |
| )+ |
| } |
| } |
| } |
| |
| #[cfg(target_pointer_width = "32")] |
| promote_and_back! { |
| i8 => f32, f64, i16, i32, isize, i64, i128 ; |
| i16 => f32, f64, i32, isize, i64, i128 ; |
| i32 => f64, i64, i128 ; |
| isize => f64, i64, i128 ; |
| i64 => i128 ; |
| u8 => f32, f64, i16, i32, isize, i64, i128, u16, u32, usize, u64, u128; |
| u16 => f32, f64, i32, isize, i64, i128, u32, usize, u64, u128; |
| u32 => f64, i64, i128, u64, u128; |
| usize => f64, i64, i128, u64, u128; |
| u64 => i128, u128; |
| } |
| |
| #[cfg(target_pointer_width = "64")] |
| promote_and_back! { |
| i8 => f32, f64, i16, i32, i64, isize, i128 ; |
| i16 => f32, f64, i32, i64, isize, i128 ; |
| i32 => f64, i64, isize, i128 ; |
| i64 => i128 ; |
| isize => i128 ; |
| u8 => f32, f64, i16, i32, i64, isize, i128, u16, u32, u64, usize, u128; |
| u16 => f32, f64, i32, i64, isize, i128, u32, u64, usize, u128; |
| u32 => f64, i64, isize, i128, u64, usize, u128; |
| u64 => i128, u128; |
| usize => i128, u128; |
| } |
| |
| // If it's Ok to cast `src` to `$dst`, it must also be Ok to cast `dst` back to |
| // `$src` |
| macro_rules! symmetric_cast_between { |
| ($($src:ident => $($dst:ident),+);+;) => { |
| mod symmetric_cast_between { |
| $( |
| mod $src { |
| mod and { |
| use quickcheck::TestResult; |
| |
| use crate::From; |
| |
| $( |
| quickcheck! { |
| fn $dst(src: $src) -> TestResult { |
| if let Ok(dst) = $dst::cast(src) { |
| TestResult::from_bool( |
| $src::cast(dst).is_ok()) |
| } else { |
| TestResult::discard() |
| } |
| } |
| } |
| )+ |
| } |
| } |
| )+ |
| } |
| } |
| } |
| |
| #[cfg(target_pointer_width = "32")] |
| symmetric_cast_between! { |
| u8 => i8 ; |
| u16 => i8, i16 ; |
| u32 => i8, i16, i32 ; |
| usize => i8, i16, i32 ; |
| u64 => i8, i16, i32, i64, isize; |
| } |
| |
| #[cfg(target_pointer_width = "64")] |
| symmetric_cast_between! { |
| u8 => i8 ; |
| u16 => i8, i16 ; |
| u32 => i8, i16, i32 ; |
| u64 => i8, i16, i32, i64, isize ; |
| usize => i8, i16, i32, i64, isize ; |
| u128 => i8, i16, i32, i64, isize, i128; |
| } |
| |
| macro_rules! from_float { |
| ($($src:ident => $($dst:ident),+);+;) => { |
| $( |
| mod $src { |
| mod inf { |
| mod to { |
| use crate::{Error, From}; |
| |
| $( |
| #[test] |
| fn $dst() { |
| let _0: $src = 0.; |
| let _1: $src = 1.; |
| let inf = _1 / _0; |
| let neg_inf = -_1 / _0; |
| |
| assert_eq!($dst::cast(inf), |
| Err(Error::Infinite)); |
| assert_eq!($dst::cast(neg_inf), |
| Err(Error::Infinite)); |
| } |
| )+ |
| } |
| } |
| |
| mod nan { |
| mod to { |
| use crate::{Error, From}; |
| |
| $( |
| #[test] |
| fn $dst() { |
| let _0: $src = 0.; |
| let nan = _0 / _0; |
| |
| assert_eq!($dst::cast(nan), |
| Err(Error::NaN)); |
| } |
| )+ |
| } |
| } |
| } |
| )+ |
| } |
| } |
| |
| from_float! { |
| f32 => i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize; |
| f64 => i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize; |
| } |
| |
| #[test] |
| fn test_fl_conversion() { |
| use crate::u128; |
| assert_eq!(u128(42.0f32), Ok(42)); |
| } |
| |
| #[test] |
| fn gh16() { |
| assert_eq!(super::u64(-0.01_f64), Ok(0)); |
| assert_eq!(super::u64(-0.99_f32), Ok(0)); |
| |
| assert_eq!(super::u32(-0.99_f64), Ok(0)); |
| assert_eq!(super::u32(-0.01_f32), Ok(0)); |
| |
| assert_eq!(super::u64(0.01_f64), Ok(0)); |
| assert_eq!(super::u64(0.99_f32), Ok(0)); |
| |
| assert_eq!(super::u32(0.99_f64), Ok(0)); |
| assert_eq!(super::u32(0.01_f32), Ok(0)); |
| } |
| |
| #[test] |
| fn gh15() { |
| assert_eq!(super::u32(32_f32.exp2()), Err(super::Error::Overflow)); |
| assert_eq!(super::u32(32_f64.exp2()), Err(super::Error::Overflow)); |
| |
| assert_eq!(super::u64(64_f32.exp2()), Err(super::Error::Overflow)); |
| assert_eq!(super::u64(64_f64.exp2()), Err(super::Error::Overflow)); |
| |
| assert_eq!(super::u8(8_f32.exp2()), Err(super::Error::Overflow)); |
| assert_eq!(super::u8(8_f64.exp2()), Err(super::Error::Overflow)); |
| |
| assert_eq!(super::u16(16_f32.exp2()), Err(super::Error::Overflow)); |
| assert_eq!(super::u16(16_f64.exp2()), Err(super::Error::Overflow)); |
| } |
| |
| #[test] |
| fn gh23_lossless_integer_max_min_to_float() { |
| // f32::MANTISSA_DIGITS = 24 |
| assert_eq!(Ok(u8::MAX), super::u8(255f32)); |
| assert_eq!(Ok(u16::MAX), super::u16(65_535f32)); |
| |
| // f64::MANTISSA_DIGITS = 53 |
| assert_eq!(Ok(u8::MAX), super::u8(255f64)); |
| assert_eq!(Ok(u16::MAX), super::u16(65_535f64)); |
| assert_eq!(Ok(u32::MAX), super::u32(4_294_967_295f64)); |
| |
| // also check negative values (not part of the original bug) |
| assert_eq!(Ok(i8::MIN), super::i8(-128f32)); |
| assert_eq!(Ok(i16::MIN), super::i16(-32_768f32)); |
| |
| assert_eq!(Ok(i8::MIN), super::i8(-128f64)); |
| assert_eq!(Ok(i16::MIN), super::i16(-32_768f64)); |
| assert_eq!(Ok(i32::MIN), super::i32(-2_147_483_648f64)); |
| } |