blob: 9bb5abfc584091e4295279849f6f17e8265aeadd [file] [log] [blame]
macro_rules! SL {
($($tts:tt)*) => { stringify!($($tts)*) };
}
macro_rules! as_expr {
($e:expr) => {$e};
}
macro_rules! check {
(@ $from:ty, $to:ty=> $(;)*) => {};
(@ $from:ty, $to:ty=> cident; $($tail:tt)*) => {
check!(@ $from, $to=> v: '\x00';);
check!(@ $from, $to=> v: '\x01';);
check!(@ $from, $to=> $($tail)*);
};
(@ $from:ty, $to:ty=> uident; $($tail:tt)*) => {
check!(@ $from, $to=> v: 0;);
check!(@ $from, $to=> v: 1;);
check!(@ $from, $to=> $($tail)*);
};
(@ $from:ty, $to:ty=> sident; $($tail:tt)*) => {
check!(@ $from, $to=> v: -1;);
check!(@ $from, $to=> v: 0;);
check!(@ $from, $to=> v: 1;);
check!(@ $from, $to=> $($tail)*);
};
(@ $from:ty, $to:ty=> fident; $($tail:tt)*) => {
check!(@ $from, $to=> v: -1.0;);
check!(@ $from, $to=> v: 0.0;);
check!(@ $from, $to=> v: 1.0;);
check!(@ $from, $to=> $($tail)*);
};
(@ $from:ty, $to:ty=> uidenta; $($tail:tt)*) => {
check!(@ $from, $to=> a: 0.0;);
check!(@ $from, $to=> a: 1.0;);
check!(@ $from, $to=> aRTN: 0.00, 0;);
check!(@ $from, $to=> aRTN: 0.25, 0;);
check!(@ $from, $to=> aRTN: 0.50, 1;);
check!(@ $from, $to=> aRTN: 0.75, 1;);
check!(@ $from, $to=> aRTN: 1.00, 1;);
check!(@ $from, $to=> aRNI: 0.00, 0;);
check!(@ $from, $to=> aRNI: 0.25, 0;);
check!(@ $from, $to=> aRNI: 0.50, 0;);
check!(@ $from, $to=> aRNI: 0.75, 0;);
check!(@ $from, $to=> aRNI: 1.00, 1;);
check!(@ $from, $to=> aRPI: 0.00, 0;);
check!(@ $from, $to=> aRPI: 0.25, 1;);
check!(@ $from, $to=> aRPI: 0.50, 1;);
check!(@ $from, $to=> aRPI: 0.75, 1;);
check!(@ $from, $to=> aRPI: 1.00, 1;);
check!(@ $from, $to=> aRTZ: 0.00, 0;);
check!(@ $from, $to=> aRTZ: 0.25, 0;);
check!(@ $from, $to=> aRTZ: 0.50, 0;);
check!(@ $from, $to=> aRTZ: 0.75, 0;);
check!(@ $from, $to=> aRTZ: 1.00, 1;);
check!(@ $from, $to=> $($tail)*);
};
(@ $from:ty, $to:ty=> sidenta; $($tail:tt)*) => {
check!(@ $from, $to=> a: -1.0;);
check!(@ $from, $to=> a: 0.0;);
check!(@ $from, $to=> a: 1.0;);
check!(@ $from, $to=> aRTN: -1.00, -1;);
check!(@ $from, $to=> aRTN: -0.75, -1;);
check!(@ $from, $to=> aRTN: -0.50, -1;);
check!(@ $from, $to=> aRTN: -0.25, 0;);
check!(@ $from, $to=> aRTN: 0.00, 0;);
check!(@ $from, $to=> aRTN: 0.25, 0;);
check!(@ $from, $to=> aRTN: 0.50, 1;);
check!(@ $from, $to=> aRTN: 0.75, 1;);
check!(@ $from, $to=> aRTN: 1.00, 1;);
check!(@ $from, $to=> aRNI: -1.00, -1;);
check!(@ $from, $to=> aRNI: -0.75, -1;);
check!(@ $from, $to=> aRNI: -0.50, -1;);
check!(@ $from, $to=> aRNI: -0.25, -1;);
check!(@ $from, $to=> aRNI: 0.00, 0;);
check!(@ $from, $to=> aRNI: 0.25, 0;);
check!(@ $from, $to=> aRNI: 0.50, 0;);
check!(@ $from, $to=> aRNI: 0.75, 0;);
check!(@ $from, $to=> aRNI: 1.00, 1;);
check!(@ $from, $to=> aRPI: -1.00, -1;);
check!(@ $from, $to=> aRPI: -0.75, 0;);
check!(@ $from, $to=> aRPI: -0.50, 0;);
check!(@ $from, $to=> aRPI: -0.25, 0;);
check!(@ $from, $to=> aRPI: 0.00, 0;);
check!(@ $from, $to=> aRPI: 0.25, 1;);
check!(@ $from, $to=> aRPI: 0.50, 1;);
check!(@ $from, $to=> aRPI: 0.75, 1;);
check!(@ $from, $to=> aRPI: 1.00, 1;);
check!(@ $from, $to=> aRTZ: -1.00, -1;);
check!(@ $from, $to=> aRTZ: -0.75, 0;);
check!(@ $from, $to=> aRTZ: -0.50, 0;);
check!(@ $from, $to=> aRTZ: -0.25, 0;);
check!(@ $from, $to=> aRTZ: 0.00, 0;);
check!(@ $from, $to=> aRTZ: 0.25, 0;);
check!(@ $from, $to=> aRTZ: 0.50, 0;);
check!(@ $from, $to=> aRTZ: 0.75, 0;);
check!(@ $from, $to=> aRTZ: 1.00, 1;);
check!(@ $from, $to=> $($tail)*);
};
(@ $from:ty, $to:ty=> fidenta; $($tail:tt)*) => {
check!(@ $from, $to=> a: -1.0;);
check!(@ $from, $to=> a: 0.0;);
check!(@ $from, $to=> a: 1.0;);
check!(@ $from, $to=> $($tail)*);
};
(@ $from:ty, $to:ty=> v: $src:expr, !$dst:expr; $($tail:tt)*) => {
{
println!("? {} => {}, v: {}, !{}", SL!($from), SL!($to), SL!($src), SL!($dst));
let src: $from = $src;
let dst: Result<$to, _> = src.value_into();
assert_eq!(dst, Err($dst(src)));
}
check!(@ $from, $to=> $($tail)*);
};
(@ $from:ty, $to:ty=> v: $src:expr; $($tail:tt)*) => {
{
println!("? {} => {}, v: {}", SL!($from), SL!($to), SL!($src));
let src: $from = $src;
let dst: Result<$to, _> = src.value_into();
assert_eq!(dst, Ok($src as $to));
}
check!(@ $from, $to=> $($tail)*);
};
(@ $from:ty, $to:ty=> qv: *; $($tail:tt)*) => {
{
extern crate quickcheck;
println!("? {} => {}, qv: *", SL!($from), SL!($to));
fn property(v: $from) -> bool {
let dst: Result<$to, _> = v.value_into();
dst == Ok(v as $to)
}
let mut qc = quickcheck::QuickCheck::new();
match qc.quicktest(property as fn($from) -> bool) {
Ok(_) => (),
Err(err) => panic!("qv {:?}", err)
}
}
check!(@ $from, $to=> $($tail)*);
};
(@ $from:ty, $to:ty=> qv: (+-$bound:expr); $($tail:tt)*) => {
{
extern crate quickcheck;
println!("? {} => {}, qv: (+- {})", SL!($from), SL!($to), SL!($bound));
fn property(v: $from) -> bool {
let dst: Result<$to, conv::FloatError<_>> = v.value_into().map_err(From::from);
if !(-$bound as $from <= v) {
dst == Err(conv::FloatError::NegOverflow(v))
} else if !(v <= $bound as $from) {
dst == Err(conv::FloatError::PosOverflow(v))
} else {
dst == Ok(v as $to)
}
}
let mut qc = quickcheck::QuickCheck::new();
match qc.quicktest(property as fn($from) -> bool) {
Ok(_) => (),
Err(err) => panic!("qv {:?}", err)
}
}
check!(@ $from, $to=> $($tail)*);
};
(@ $from:ty, $to:ty=> qv: (, $bound:expr); $($tail:tt)*) => {
{
extern crate quickcheck;
println!("? {} => {}, qv: (, {})", SL!($from), SL!($to), SL!($bound));
fn property(v: $from) -> bool {
let dst: Result<$to, conv::FloatError<_>> = v.value_into().map_err(From::from);
if !(v <= $bound as $from) {
dst == Err(conv::FloatError::PosOverflow(v))
} else {
dst == Ok(v as $to)
}
}
let mut qc = quickcheck::QuickCheck::new();
match qc.quicktest(property as fn($from) -> bool) {
Ok(_) => (),
Err(err) => panic!("qv {:?}", err)
}
}
check!(@ $from, $to=> $($tail)*);
};
(@ $from:ty, $to:ty=> qv: +; $($tail:tt)*) => {
{
extern crate quickcheck;
println!("? {} => {}, qv: +", SL!($from), SL!($to));
fn property(v: $from) -> bool {
let dst: Result<$to, conv::FloatError<_>> = v.value_into().map_err(From::from);
if !(0 <= v) {
dst == Err(conv::FloatError::NegOverflow(v))
} else {
dst == Ok(v as $to)
}
}
let mut qc = quickcheck::QuickCheck::new();
match qc.quicktest(property as fn($from) -> bool) {
Ok(_) => (),
Err(err) => panic!("qv {:?}", err)
}
}
check!(@ $from, $to=> $($tail)*);
};
(@ $from:ty, $to:ty=> qv: +$max:ty=> $($tail:tt)*) => {
{
extern crate quickcheck;
println!("? {} => {}, qv: +{}", SL!($from), SL!($to), SL!($max));
fn property(v: $from) -> bool {
let dst: Result<$to, conv::FloatError<_>> = v.value_into().map_err(From::from);
if !(v <= <$max>::max_value() as $from) {
dst == Err(conv::FloatError::PosOverflow(v))
} else {
dst == Ok(v as $to)
}
}
let mut qc = quickcheck::QuickCheck::new();
match qc.quicktest(property as fn($from) -> bool) {
Ok(_) => (),
Err(err) => panic!("qv {:?}", err)
}
}
check!(@ $from, $to=> $($tail)*);
};
(@ $from:ty, $to:ty=> qv: $bound:ty=> $($tail:tt)*) => {
{
extern crate quickcheck;
println!("? {} => {}, qv: {}", SL!($from), SL!($to), SL!($bound));
fn property(v: $from) -> bool {
let dst: Result<$to, conv::FloatError<_>> = v.value_into().map_err(From::from);
if !(<$bound>::min_value() as $from <= v) {
dst == Err(conv::FloatError::NegOverflow(v))
} else if !(v <= <$bound>::max_value() as $from) {
dst == Err(conv::FloatError::PosOverflow(v))
} else {
dst == Ok(v as $to)
}
}
let mut qc = quickcheck::QuickCheck::new();
match qc.quicktest(property as fn($from) -> bool) {
Ok(_) => (),
Err(err) => panic!("qv {:?}", err)
}
}
check!(@ $from, $to=> $($tail)*);
};
(@ $from:ty, $to:ty=> qv: $min:ty, $max:ty=> $($tail:tt)*) => {
{
extern crate quickcheck;
println!("? {} => {}, qv: {}, {}", SL!($from), SL!($to), SL!($min), SL!($max));
fn property(v: $from) -> bool {
let dst: Result<$to, conv::FloatError<_>> = v.value_into().map_err(From::from);
if !(<$min>::min_value() as $from <= v) {
dst == Err(conv::FloatError::NegOverflow(v))
} else if !(v <= <$max>::max_value() as $from) {
dst == Err(conv::FloatError::PosOverflow(v))
} else {
dst == Ok(v as $to)
}
}
let mut qc = quickcheck::QuickCheck::new();
match qc.quicktest(property as fn($from) -> bool) {
Ok(_) => (),
Err(err) => panic!("qv {:?}", err)
}
}
check!(@ $from, $to=> $($tail)*);
};
(@ $from:ty, $to:ty=> a: $src:expr, !$dst:expr; $($tail:tt)*) => {
{
println!("? {} => {}, a: {}, !{}", SL!($from), SL!($to), SL!($src), SL!($dst));
let src: $from = $src;
let dst: Result<$to, _> = src.approx_as();
assert_eq!(dst, Err($dst(src)));
}
check!(@ $from, $to=> $($tail)*);
};
(@ $from:ty, $to:ty=> a: $src:expr, $dst:expr; $($tail:tt)*) => {
{
println!("? {} => {}, a: {}, {}", SL!($from), SL!($to), SL!($src), SL!($dst));
let src: $from = $src;
let dst: Result<$to, _> = src.approx_as();
assert_eq!(dst, Ok($dst));
}
check!(@ $from, $to=> $($tail)*);
};
(@ $from:ty, $to:ty=> a: $src:expr; $($tail:tt)*) => {
{
println!("? {} => {}, a: {}", SL!($from), SL!($to), SL!($src));
let src: $from = $src;
let dst: Result<$to, _> = src.approx_as();
assert_eq!(dst, Ok($src as $to));
}
check!(@ $from, $to=> $($tail)*);
};
(@ $from:ty, $to:ty=> qa: *; $($tail:tt)*) => {
{
println!("? {} => {}, qa: *", SL!($from), SL!($to));
extern crate quickcheck;
fn property(v: $from) -> bool {
let dst: Result<$to, _> = v.approx_as();
dst == Ok(v as $to)
}
let mut qc = quickcheck::QuickCheck::new();
match qc.quicktest(property as fn($from) -> bool) {
Ok(_) => (),
Err(err) => panic!("qa {:?}", err)
}
}
check!(@ $from, $to=> $($tail)*);
};
(@ $from:ty, $to:ty=> qa: +; $($tail:tt)*) => {
{
extern crate quickcheck;
println!("? {} => {}, qa: +", SL!($from), SL!($to));
fn property(v: $from) -> bool {
let dst: Result<$to, conv::FloatError<_>> = v.approx_as().map_err(From::from);
if !(0 <= v) {
dst == Err(conv::FloatError::NegOverflow(v))
} else {
dst == Ok(v as $to)
}
}
let mut qc = quickcheck::QuickCheck::new();
match qc.quicktest(property as fn($from) -> bool) {
Ok(_) => (),
Err(err) => panic!("qa {:?}", err)
}
}
check!(@ $from, $to=> $($tail)*);
};
(@ $from:ty, $to:ty=> qa: +$max:ty=> $($tail:tt)*) => {
{
extern crate quickcheck;
println!("? {} => {}, qa: +{}", SL!($from), SL!($to), SL!($max));
fn property(v: $from) -> bool {
let dst: Result<$to, conv::FloatError<_>> = v.approx_as().map_err(From::from);
if !(v <= <$max>::max_value() as $from) {
dst == Err(conv::FloatError::PosOverflow(v))
} else {
dst == Ok(v as $to)
}
}
let mut qc = quickcheck::QuickCheck::new();
match qc.quicktest(property as fn($from) -> bool) {
Ok(_) => (),
Err(err) => panic!("qa {:?}", err)
}
}
check!(@ $from, $to=> $($tail)*);
};
(@ $from:ty, $to:ty=> qa: $bound:ty=> $($tail:tt)*) => {
{
extern crate quickcheck;
println!("? {} => {}, qa: {}", SL!($from), SL!($to), SL!($bound));
fn property(v: $from) -> bool {
let dst: Result<$to, conv::FloatError<_>> = v.approx_as().map_err(From::from);
if !(<$bound>::min_value() as $from <= v) {
dst == Err(conv::FloatError::NegOverflow(v))
} else if !(v <= <$bound>::max_value() as $from) {
dst == Err(conv::FloatError::PosOverflow(v))
} else {
dst == Ok(v as $to)
}
}
let mut qc = quickcheck::QuickCheck::new();
match qc.quicktest(property as fn($from) -> bool) {
Ok(_) => (),
Err(err) => panic!("qa {:?}", err)
}
}
check!(@ $from, $to=> $($tail)*);
};
(@ $from:ty, $to:ty=> qaW: *; $($tail:tt)*) => {
{
extern crate quickcheck;
println!("? {} => {}, qaW: *", SL!($from), SL!($to));
fn property(v: $from) -> bool {
let dst: Result<$to, _> = v.approx_as_by::<_, Wrapping>();
dst == Ok(v as $to)
}
let mut qc = quickcheck::QuickCheck::new();
match qc.quicktest(property as fn($from) -> bool) {
Ok(_) => (),
Err(err) => panic!("qaW {:?}", err)
}
}
check!(@ $from, $to=> $($tail)*);
};
(@ $from:ty, $to:ty=> aRTN: $src:expr, $dst:expr; $($tail:tt)*) => {
{
println!("? {} => {}, aRTN: {}, {}", SL!($from), SL!($to), SL!($src), SL!($dst));
let src: $from = $src;
let dst: Result<$to, _> = src.approx_by::<conv::RoundToNearest>();
assert_eq!(dst, Ok($dst));
}
check!(@ $from, $to=> $($tail)*);
};
(@ $from:ty, $to:ty=> aRNI: $src:expr, $dst:expr; $($tail:tt)*) => {
{
println!("? {} => {}, aRNI: {}, {}", SL!($from), SL!($to), SL!($src), SL!($dst));
let src: $from = $src;
let dst: Result<$to, _> = src.approx_by::<conv::RoundToNegInf>();
assert_eq!(dst, Ok($dst));
}
check!(@ $from, $to=> $($tail)*);
};
(@ $from:ty, $to:ty=> aRPI: $src:expr, $dst:expr; $($tail:tt)*) => {
{
println!("? {} => {}, aRPI: {}, {}", SL!($from), SL!($to), SL!($src), SL!($dst));
let src: $from = $src;
let dst: Result<$to, _> = src.approx_by::<conv::RoundToPosInf>();
assert_eq!(dst, Ok($dst));
}
check!(@ $from, $to=> $($tail)*);
};
(@ $from:ty, $to:ty=> aRTZ: $src:expr, $dst:expr; $($tail:tt)*) => {
{
println!("? {} => {}, aRTZ: {}, {}", SL!($from), SL!($to), SL!($src), SL!($dst));
let src: $from = $src;
let dst: Result<$to, _> = src.approx_by::<conv::RoundToZero>();
assert_eq!(dst, Ok($dst));
}
check!(@ $from, $to=> $($tail)*);
};
($from:ty, $to:ty=> $($tail:tt)*) => {
check! { @ $from, $to=> $($tail)*; }
};
}
macro_rules! for_bitness {
(32 {$($bits32:tt)*} 64 {$($bits64:tt)*}) => {
as_expr!(
{
#[cfg(target_pointer_width="32")]
fn for_bitness() {
$($bits32)*
}
#[cfg(target_pointer_width="64")]
fn for_bitness() {
$($bits64)*
}
for_bitness()
}
)
};
}