// 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)); }