blob: 161a0220e639480d417db51eaa4da809214c8546 [file] [log] [blame]
// 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));
}