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::(); 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::(); 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::(); 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::(); 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() } ) }; }