From 0966f39628fef74ab42785425a34001661329ecd Mon Sep 17 00:00:00 2001 From: apopiak Date: Wed, 25 Nov 2015 22:09:35 +0100 Subject: [PATCH 1/2] add impl_to_primitive_float_to_int_or_uint macro with bounds checking + tests --- src/traits.rs | 80 ++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 70 insertions(+), 10 deletions(-) diff --git a/src/traits.rs b/src/traits.rs index 3cf0268935..040dc28599 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -1136,30 +1136,42 @@ macro_rules! impl_to_primitive_float_to_float { ) } +macro_rules! impl_to_primitive_float_to_int_or_uint { + ($SrcT:ident, $DstT:ident, $slf:expr) => ( + { + if $slf >= $DstT::MIN as $SrcT && $slf <= $DstT::MAX as $SrcT { + Some($slf as $DstT) + } else { + None + } + } + ) +} + macro_rules! impl_to_primitive_float { ($T:ident) => ( impl ToPrimitive for $T { #[inline] - fn to_isize(&self) -> Option { Some(*self as isize) } + fn to_isize(&self) -> Option { impl_to_primitive_float_to_int_or_uint!($T, isize, *self) } #[inline] - fn to_i8(&self) -> Option { Some(*self as i8) } + fn to_i8(&self) -> Option { impl_to_primitive_float_to_int_or_uint!($T, i8, *self) } #[inline] - fn to_i16(&self) -> Option { Some(*self as i16) } + fn to_i16(&self) -> Option { impl_to_primitive_float_to_int_or_uint!($T, i16, *self) } #[inline] - fn to_i32(&self) -> Option { Some(*self as i32) } + fn to_i32(&self) -> Option { impl_to_primitive_float_to_int_or_uint!($T, i32, *self) } #[inline] - fn to_i64(&self) -> Option { Some(*self as i64) } + fn to_i64(&self) -> Option { impl_to_primitive_float_to_int_or_uint!($T, i64, *self) } #[inline] - fn to_usize(&self) -> Option { Some(*self as usize) } + fn to_usize(&self) -> Option { impl_to_primitive_float_to_int_or_uint!($T, usize, *self) } #[inline] - fn to_u8(&self) -> Option { Some(*self as u8) } + fn to_u8(&self) -> Option { impl_to_primitive_float_to_int_or_uint!($T, u8, *self) } #[inline] - fn to_u16(&self) -> Option { Some(*self as u16) } + fn to_u16(&self) -> Option { impl_to_primitive_float_to_int_or_uint!($T, u16, *self) } #[inline] - fn to_u32(&self) -> Option { Some(*self as u32) } + fn to_u32(&self) -> Option { impl_to_primitive_float_to_int_or_uint!($T, u32, *self) } #[inline] - fn to_u64(&self) -> Option { Some(*self as u64) } + fn to_u64(&self) -> Option { impl_to_primitive_float_to_int_or_uint!($T, u64, *self) } #[inline] fn to_f32(&self) -> Option { impl_to_primitive_float_to_float!($T, f32, *self) } @@ -2448,3 +2460,51 @@ fn integer_decode_f64(f: f64) -> (u64, i16, i8) { float_impl!(f32 integer_decode_f32); float_impl!(f64 integer_decode_f64); + +#[test] +fn test_cast_to_int() { + let big_f: f64 = 1.0e123; + let normal_f: f64 = 1.0; + let small_f: f64 = -1.0e123; + assert_eq!(None, cast::(big_f)); + assert_eq!(None, cast::(big_f)); + assert_eq!(None, cast::(big_f)); + assert_eq!(None, cast::(big_f)); + assert_eq!(None, cast::(big_f)); + + assert_eq!(Some(normal_f as isize), cast::(normal_f)); + assert_eq!(Some(normal_f as i8), cast::(normal_f)); + assert_eq!(Some(normal_f as i16), cast::(normal_f)); + assert_eq!(Some(normal_f as i32), cast::(normal_f)); + assert_eq!(Some(normal_f as i64), cast::(normal_f)); + + assert_eq!(None, cast::(small_f)); + assert_eq!(None, cast::(small_f)); + assert_eq!(None, cast::(small_f)); + assert_eq!(None, cast::(small_f)); + assert_eq!(None, cast::(small_f)); +} + +#[test] +fn test_cast_to_unsigned_int() { + let big_f: f64 = 1.0e123; + let normal_f: f64 = 1.0; + let small_f: f64 = -1.0e123; + assert_eq!(None, cast::(big_f)); + assert_eq!(None, cast::(big_f)); + assert_eq!(None, cast::(big_f)); + assert_eq!(None, cast::(big_f)); + assert_eq!(None, cast::(big_f)); + + assert_eq!(Some(normal_f as usize), cast::(normal_f)); + assert_eq!(Some(normal_f as u8), cast::(normal_f)); + assert_eq!(Some(normal_f as u16), cast::(normal_f)); + assert_eq!(Some(normal_f as u32), cast::(normal_f)); + assert_eq!(Some(normal_f as u64), cast::(normal_f)); + + assert_eq!(None, cast::(small_f)); + assert_eq!(None, cast::(small_f)); + assert_eq!(None, cast::(small_f)); + assert_eq!(None, cast::(small_f)); + assert_eq!(None, cast::(small_f)); +} From 44ed68bec6b9cbed8153bb7cd85657e0104b50d0 Mon Sep 17 00:00:00 2001 From: Alexander Popiak Date: Thu, 26 Nov 2015 00:55:03 +0100 Subject: [PATCH 2/2] address review comments (truncate float) --- src/traits.rs | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/traits.rs b/src/traits.rs index 040dc28599..d60e84be1a 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -1136,10 +1136,11 @@ macro_rules! impl_to_primitive_float_to_float { ) } -macro_rules! impl_to_primitive_float_to_int_or_uint { +macro_rules! impl_to_primitive_float_to_integer { ($SrcT:ident, $DstT:ident, $slf:expr) => ( { - if $slf >= $DstT::MIN as $SrcT && $slf <= $DstT::MAX as $SrcT { + let t = $slf.trunc(); + if t >= $DstT::MIN as $SrcT && t <= $DstT::MAX as $SrcT { Some($slf as $DstT) } else { None @@ -1152,26 +1153,26 @@ macro_rules! impl_to_primitive_float { ($T:ident) => ( impl ToPrimitive for $T { #[inline] - fn to_isize(&self) -> Option { impl_to_primitive_float_to_int_or_uint!($T, isize, *self) } + fn to_isize(&self) -> Option { impl_to_primitive_float_to_integer!($T, isize, *self) } #[inline] - fn to_i8(&self) -> Option { impl_to_primitive_float_to_int_or_uint!($T, i8, *self) } + fn to_i8(&self) -> Option { impl_to_primitive_float_to_integer!($T, i8, *self) } #[inline] - fn to_i16(&self) -> Option { impl_to_primitive_float_to_int_or_uint!($T, i16, *self) } + fn to_i16(&self) -> Option { impl_to_primitive_float_to_integer!($T, i16, *self) } #[inline] - fn to_i32(&self) -> Option { impl_to_primitive_float_to_int_or_uint!($T, i32, *self) } + fn to_i32(&self) -> Option { impl_to_primitive_float_to_integer!($T, i32, *self) } #[inline] - fn to_i64(&self) -> Option { impl_to_primitive_float_to_int_or_uint!($T, i64, *self) } + fn to_i64(&self) -> Option { impl_to_primitive_float_to_integer!($T, i64, *self) } #[inline] - fn to_usize(&self) -> Option { impl_to_primitive_float_to_int_or_uint!($T, usize, *self) } + fn to_usize(&self) -> Option { impl_to_primitive_float_to_integer!($T, usize, *self) } #[inline] - fn to_u8(&self) -> Option { impl_to_primitive_float_to_int_or_uint!($T, u8, *self) } + fn to_u8(&self) -> Option { impl_to_primitive_float_to_integer!($T, u8, *self) } #[inline] - fn to_u16(&self) -> Option { impl_to_primitive_float_to_int_or_uint!($T, u16, *self) } + fn to_u16(&self) -> Option { impl_to_primitive_float_to_integer!($T, u16, *self) } #[inline] - fn to_u32(&self) -> Option { impl_to_primitive_float_to_int_or_uint!($T, u32, *self) } + fn to_u32(&self) -> Option { impl_to_primitive_float_to_integer!($T, u32, *self) } #[inline] - fn to_u64(&self) -> Option { impl_to_primitive_float_to_int_or_uint!($T, u64, *self) } + fn to_u64(&self) -> Option { impl_to_primitive_float_to_integer!($T, u64, *self) } #[inline] fn to_f32(&self) -> Option { impl_to_primitive_float_to_float!($T, f32, *self) }