From d9d1dfc1955fabb7ee3a55e9c84cdcd5aad67417 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Sun, 15 Sep 2013 09:50:17 -0700 Subject: std: Replace num::IntConvertible with {To,From}Primitive --- src/libstd/num/num.rs | 424 +++++++++++++++++++++++++++++++++++++--------- src/libstd/num/strconv.rs | 26 +-- src/libstd/prelude.rs | 2 +- src/libstd/rand/mod.rs | 4 +- 4 files changed, 357 insertions(+), 99 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/num/num.rs b/src/libstd/num/num.rs index 95b1057dfd0..a8c85184664 100644 --- a/src/libstd/num/num.rs +++ b/src/libstd/num/num.rs @@ -32,11 +32,6 @@ pub trait Num: Eq + Zero + One + Div + Rem {} -pub trait IntConvertible { - fn to_int(&self) -> int; - fn from_int(n: int) -> Self; -} - pub trait Orderable: Ord { // These should be methods on `Ord`, with overridable default implementations. We don't want // to encumber all implementors of Ord by requiring them to implement these functions, but at @@ -353,6 +348,298 @@ pub trait Float: Real #[inline(always)] pub fn ln_1p(value: T) -> T { value.ln_1p() } #[inline(always)] pub fn mul_add(a: T, b: T, c: T) -> T { a.mul_add(b, c) } +/// A generic trait for converting a value to a number. +pub trait ToPrimitive { + /// Converts the value of `self` to an `int`. + fn to_int(&self) -> Option; + + /// Converts the value of `self` to an `i8`. + #[inline] + fn to_i8(&self) -> Option { + // XXX: Check for range. + self.to_int().and_then(|x| Some(x as i8)) + } + + /// Converts the value of `self` to an `i16`. + #[inline] + fn to_i16(&self) -> Option { + // XXX: Check for range. + self.to_int().and_then(|x| Some(x as i16)) + } + + /// Converts the value of `self` to an `i32`. + #[inline] + fn to_i32(&self) -> Option { + // XXX: Check for range. + self.to_int().and_then(|x| Some(x as i32)) + } + + /// Converts the value of `self` to an `i64`. + #[inline] + fn to_i64(&self) -> Option { + // XXX: Check for range. + self.to_int().and_then(|x| Some(x as i64)) + } + + /// Converts the value of `self` to an `uint`. + fn to_uint(&self) -> Option; + + /// Converts the value of `self` to an `u8`. + #[inline] + fn to_u8(&self) -> Option { + // XXX: Check for range. + self.to_uint().and_then(|x| Some(x as u8)) + } + + /// Converts the value of `self` to an `u16`. + #[inline] + fn to_u16(&self) -> Option { + // XXX: Check for range. + self.to_uint().and_then(|x| Some(x as u16)) + } + + /// Converts the value of `self` to an `u32`. + #[inline] + fn to_u32(&self) -> Option { + // XXX: Check for range. + self.to_uint().and_then(|x| Some(x as u32)) + } + + /// Converts the value of `self` to an `u64`. + #[inline] + fn to_u64(&self) -> Option { + // XXX: Check for range. + self.to_uint().and_then(|x| Some(x as u64)) + } + + /// Converts the value of `self` to an `f32`. + #[inline] + fn to_f32(&self) -> Option { + // XXX: Check for range. + self.to_float().and_then(|x| Some(x as f32)) + } + + /// Converts the value of `self` to an `f64`. + #[inline] + fn to_f64(&self) -> Option { + // XXX: Check for range. + self.to_float().and_then(|x| Some(x as f64)) + } +} + +macro_rules! impl_to_primitive( + ($T:ty) => ( + impl ToPrimitive for $T { + #[inline] fn to_int(&self) -> Option { Some(*self as int) } + #[inline] fn to_i8(&self) -> Option { Some(*self as i8) } + #[inline] fn to_i16(&self) -> Option { Some(*self as i16) } + #[inline] fn to_i32(&self) -> Option { Some(*self as i32) } + #[inline] fn to_i64(&self) -> Option { Some(*self as i64) } + + #[inline] fn to_uint(&self) -> Option { Some(*self as uint) } + #[inline] fn to_u8(&self) -> Option { Some(*self as u8) } + #[inline] fn to_u16(&self) -> Option { Some(*self as u16) } + #[inline] fn to_u32(&self) -> Option { Some(*self as u32) } + #[inline] fn to_u64(&self) -> Option { Some(*self as u64) } + + #[inline] fn to_float(&self) -> Option { Some(*self as float) } + #[inline] fn to_f32(&self) -> Option { Some(*self as f32) } + #[inline] fn to_f64(&self) -> Option { Some(*self as f64) } + } + ) +) + +impl_to_primitive!(u8) +impl_to_primitive!(u16) +impl_to_primitive!(u32) +impl_to_primitive!(u64) +impl_to_primitive!(uint) +impl_to_primitive!(i8) +impl_to_primitive!(i16) +impl_to_primitive!(i32) +impl_to_primitive!(i64) +impl_to_primitive!(int) +impl_to_primitive!(f32) +impl_to_primitive!(f64) +impl_to_primitive!(float) + +/// A generic trait for converting a number to a value. +pub trait FromPrimitive { + /// Convert an `int` to return an optional value of this type. If the + /// value cannot be represented by this value, the `None` is returned. + fn from_int(n: int) -> Option; + + /// Convert an `i8` to return an optional value of this type. If the + /// type cannot be represented by this value, the `None` is returned. + #[inline] + fn from_i8(n: i8) -> Option { + FromPrimitive::from_int(n as int) + } + + /// Convert an `i16` to return an optional value of this type. If the + /// type cannot be represented by this value, the `None` is returned. + #[inline] + fn from_i16(n: i16) -> Option { + FromPrimitive::from_int(n as int) + } + + /// Convert an `i32` to return an optional value of this type. If the + /// type cannot be represented by this value, the `None` is returned. + #[inline] + fn from_i32(n: i32) -> Option { + FromPrimitive::from_int(n as int) + } + + /// Convert an `i64` to return an optional value of this type. If the + /// type cannot be represented by this value, the `None` is returned. + #[inline] + fn from_i64(n: i64) -> Option { + FromPrimitive::from_int(n as int) + } + + /// Convert an `uint` to return an optional value of this type. If the + /// type cannot be represented by this value, the `None` is returned. + fn from_uint(n: uint) -> Option; + + /// Convert an `u8` to return an optional value of this type. If the + /// type cannot be represented by this value, the `None` is returned. + #[inline] + fn from_u8(n: u8) -> Option { + FromPrimitive::from_uint(n as uint) + } + + /// Convert an `u16` to return an optional value of this type. If the + /// type cannot be represented by this value, the `None` is returned. + #[inline] + fn from_u16(n: u16) -> Option { + FromPrimitive::from_uint(n as uint) + } + + /// Convert an `u32` to return an optional value of this type. If the + /// type cannot be represented by this value, the `None` is returned. + #[inline] + fn from_u32(n: u32) -> Option { + FromPrimitive::from_uint(n as uint) + } + + /// Convert an `u64` to return an optional value of this type. If the + /// type cannot be represented by this value, the `None` is returned. + #[inline] + fn from_u64(n: u64) -> Option { + FromPrimitive::from_uint(n as uint) + } + + /// Convert a `f32` to return an optional value of this type. If the + /// type cannot be represented by this value, the `None` is returned. + #[inline] + fn from_f32(n: f32) -> Option { + FromPrimitive::from_float(n as float) + } + + /// Convert a `f64` to return an optional value of this type. If the + /// type cannot be represented by this value, the `None` is returned. + #[inline] + fn from_f64(n: f64) -> Option { + FromPrimitive::from_float(n as float) + } +} + +/// A utility function that just calls `FromPrimitive::from_int`. +pub fn from_int(n: int) -> Option { + FromPrimitive::from_int(n) +} + +/// A utility function that just calls `FromPrimitive::from_i8`. +pub fn from_i8(n: i8) -> Option { + FromPrimitive::from_i8(n) +} + +/// A utility function that just calls `FromPrimitive::from_i16`. +pub fn from_i16(n: i16) -> Option { + FromPrimitive::from_i16(n) +} + +/// A utility function that just calls `FromPrimitive::from_i32`. +pub fn from_i32(n: i32) -> Option { + FromPrimitive::from_i32(n) +} + +/// A utility function that just calls `FromPrimitive::from_i64`. +pub fn from_i64(n: i64) -> Option { + FromPrimitive::from_i64(n) +} + +/// A utility function that just calls `FromPrimitive::from_uint`. +pub fn from_uint(n: uint) -> Option { + FromPrimitive::from_uint(n) +} + +/// A utility function that just calls `FromPrimitive::from_u8`. +pub fn from_u8(n: u8) -> Option { + FromPrimitive::from_u8(n) +} + +/// A utility function that just calls `FromPrimitive::from_u16`. +pub fn from_u16(n: u16) -> Option { + FromPrimitive::from_u16(n) +} + +/// A utility function that just calls `FromPrimitive::from_u32`. +pub fn from_u32(n: u32) -> Option { + FromPrimitive::from_u32(n) +} + +/// A utility function that just calls `FromPrimitive::from_u64`. +pub fn from_u64(n: u64) -> Option { + FromPrimitive::from_u64(n) +} + +/// A utility function that just calls `FromPrimitive::from_f32`. +pub fn from_f32(n: f32) -> Option { + FromPrimitive::from_f32(n) +} + +/// A utility function that just calls `FromPrimitive::from_f64`. +pub fn from_f64(n: f64) -> Option { + FromPrimitive::from_f64(n) +} + +macro_rules! impl_from_primitive( + ($T:ty) => ( + impl FromPrimitive for $T { + #[inline] fn from_int(n: int) -> Option<$T> { Some(n as $T) } + #[inline] fn from_i8(n: i8) -> Option<$T> { Some(n as $T) } + #[inline] fn from_i16(n: i16) -> Option<$T> { Some(n as $T) } + #[inline] fn from_i32(n: i32) -> Option<$T> { Some(n as $T) } + #[inline] fn from_i64(n: i64) -> Option<$T> { Some(n as $T) } + + #[inline] fn from_uint(n: uint) -> Option<$T> { Some(n as $T) } + #[inline] fn from_u8(n: u8) -> Option<$T> { Some(n as $T) } + #[inline] fn from_u16(n: u16) -> Option<$T> { Some(n as $T) } + #[inline] fn from_u32(n: u32) -> Option<$T> { Some(n as $T) } + #[inline] fn from_u64(n: u64) -> Option<$T> { Some(n as $T) } + + #[inline] fn from_float(n: float) -> Option<$T> { Some(n as $T) } + #[inline] fn from_f32(n: f32) -> Option<$T> { Some(n as $T) } + #[inline] fn from_f64(n: f64) -> Option<$T> { Some(n as $T) } + } + ) +) + +impl_from_primitive!(u8) +impl_from_primitive!(u16) +impl_from_primitive!(u32) +impl_from_primitive!(u64) +impl_from_primitive!(uint) +impl_from_primitive!(i8) +impl_from_primitive!(i16) +impl_from_primitive!(i32) +impl_from_primitive!(i64) +impl_from_primitive!(int) +impl_from_primitive!(f32) +impl_from_primitive!(f64) +impl_from_primitive!(float) + /// Cast from one machine scalar to another /// /// # Example @@ -363,54 +650,24 @@ pub trait Float: Real /// ``` /// #[inline] -pub fn cast(n: T) -> U { +pub fn cast(n: T) -> Option { NumCast::from(n) } /// An interface for casting between machine scalars -pub trait NumCast { - fn from(n: T) -> Self; - - fn to_u8(&self) -> u8; - fn to_u16(&self) -> u16; - fn to_u32(&self) -> u32; - fn to_u64(&self) -> u64; - fn to_uint(&self) -> uint; - - fn to_i8(&self) -> i8; - fn to_i16(&self) -> i16; - fn to_i32(&self) -> i32; - fn to_i64(&self) -> i64; - fn to_int(&self) -> int; - - fn to_f32(&self) -> f32; - fn to_f64(&self) -> f64; +pub trait NumCast: ToPrimitive { + fn from(n: T) -> Option; } macro_rules! impl_num_cast( ($T:ty, $conv:ident) => ( impl NumCast for $T { #[inline] - fn from(n: N) -> $T { + fn from(n: N) -> Option<$T> { // `$conv` could be generated using `concat_idents!`, but that // macro seems to be broken at the moment n.$conv() } - - #[inline] fn to_u8(&self) -> u8 { *self as u8 } - #[inline] fn to_u16(&self) -> u16 { *self as u16 } - #[inline] fn to_u32(&self) -> u32 { *self as u32 } - #[inline] fn to_u64(&self) -> u64 { *self as u64 } - #[inline] fn to_uint(&self) -> uint { *self as uint } - - #[inline] fn to_i8(&self) -> i8 { *self as i8 } - #[inline] fn to_i16(&self) -> i16 { *self as i16 } - #[inline] fn to_i32(&self) -> i32 { *self as i32 } - #[inline] fn to_i64(&self) -> i64 { *self as i64 } - #[inline] fn to_int(&self) -> int { *self as int } - - #[inline] fn to_f32(&self) -> f32 { *self as f32 } - #[inline] fn to_f64(&self) -> f64 { *self as f64 } } ) ) @@ -461,7 +718,7 @@ pub fn pow_with_uint+Mul>(radix: uint, pow: uin if radix == 0u { return _0; } let mut my_pow = pow; let mut total = _1; - let mut multiplier = cast(radix); + let mut multiplier = cast(radix).unwrap(); while (my_pow > 0u) { if my_pow % 2u == 1u { total = total * multiplier; @@ -543,11 +800,11 @@ pub trait CheckedDiv: Div { /// Helper function for testing numeric operations #[cfg(test)] pub fn test_num(ten: T, two: T) { - assert_eq!(ten.add(&two), cast(12)); - assert_eq!(ten.sub(&two), cast(8)); - assert_eq!(ten.mul(&two), cast(20)); - assert_eq!(ten.div(&two), cast(5)); - assert_eq!(ten.rem(&two), cast(0)); + assert_eq!(ten.add(&two), cast(12).unwrap()); + assert_eq!(ten.sub(&two), cast(8).unwrap()); + assert_eq!(ten.mul(&two), cast(20).unwrap()); + assert_eq!(ten.div(&two), cast(5).unwrap()); + assert_eq!(ten.rem(&two), cast(0).unwrap()); assert_eq!(ten.add(&two), ten + two); assert_eq!(ten.sub(&two), ten - two); @@ -566,44 +823,45 @@ mod tests { ($_20:expr) => ({ let _20 = $_20; - assert_eq!(20u, _20.to_uint()); - assert_eq!(20u8, _20.to_u8()); - assert_eq!(20u16, _20.to_u16()); - assert_eq!(20u32, _20.to_u32()); - assert_eq!(20u64, _20.to_u64()); - assert_eq!(20i, _20.to_int()); - assert_eq!(20i8, _20.to_i8()); - assert_eq!(20i16, _20.to_i16()); - assert_eq!(20i32, _20.to_i32()); - assert_eq!(20i64, _20.to_i64()); - assert_eq!(20f32, _20.to_f32()); - assert_eq!(20f64, _20.to_f64()); - - assert_eq!(_20, NumCast::from(20u)); - assert_eq!(_20, NumCast::from(20u8)); - assert_eq!(_20, NumCast::from(20u16)); - assert_eq!(_20, NumCast::from(20u32)); - assert_eq!(_20, NumCast::from(20u64)); - assert_eq!(_20, NumCast::from(20i)); - assert_eq!(_20, NumCast::from(20i8)); - assert_eq!(_20, NumCast::from(20i16)); - assert_eq!(_20, NumCast::from(20i32)); - assert_eq!(_20, NumCast::from(20i64)); - assert_eq!(_20, NumCast::from(20f32)); - assert_eq!(_20, NumCast::from(20f64)); - - assert_eq!(_20, cast(20u)); - assert_eq!(_20, cast(20u8)); - assert_eq!(_20, cast(20u16)); - assert_eq!(_20, cast(20u32)); - assert_eq!(_20, cast(20u64)); - assert_eq!(_20, cast(20i)); - assert_eq!(_20, cast(20i8)); - assert_eq!(_20, cast(20i16)); - assert_eq!(_20, cast(20i32)); - assert_eq!(_20, cast(20i64)); - assert_eq!(_20, cast(20f32)); - assert_eq!(_20, cast(20f64)); + assert_eq!(20u, _20.to_uint().unwrap()); + assert_eq!(20u8, _20.to_u8().unwrap()); + assert_eq!(20u16, _20.to_u16().unwrap()); + assert_eq!(20u32, _20.to_u32().unwrap()); + assert_eq!(20u64, _20.to_u64().unwrap()); + assert_eq!(20i, _20.to_int().unwrap()); + assert_eq!(20i8, _20.to_i8().unwrap()); + assert_eq!(20i16, _20.to_i16().unwrap()); + assert_eq!(20i32, _20.to_i32().unwrap()); + assert_eq!(20i64, _20.to_i64().unwrap()); + assert_eq!(20f, _20.to_float().unwrap()); + assert_eq!(20f32, _20.to_f32().unwrap()); + assert_eq!(20f64, _20.to_f64().unwrap()); + + assert_eq!(_20, NumCast::from(20u).unwrap()); + assert_eq!(_20, NumCast::from(20u8).unwrap()); + assert_eq!(_20, NumCast::from(20u16).unwrap()); + assert_eq!(_20, NumCast::from(20u32).unwrap()); + assert_eq!(_20, NumCast::from(20u64).unwrap()); + assert_eq!(_20, NumCast::from(20i).unwrap()); + assert_eq!(_20, NumCast::from(20i8).unwrap()); + assert_eq!(_20, NumCast::from(20i16).unwrap()); + assert_eq!(_20, NumCast::from(20i32).unwrap()); + assert_eq!(_20, NumCast::from(20i64).unwrap()); + assert_eq!(_20, NumCast::from(20f32).unwrap()); + assert_eq!(_20, NumCast::from(20f64).unwrap()); + + assert_eq!(_20, cast(20u).unwrap()); + assert_eq!(_20, cast(20u8).unwrap()); + assert_eq!(_20, cast(20u16).unwrap()); + assert_eq!(_20, cast(20u32).unwrap()); + assert_eq!(_20, cast(20u64).unwrap()); + assert_eq!(_20, cast(20i).unwrap()); + assert_eq!(_20, cast(20i8).unwrap()); + assert_eq!(_20, cast(20i16).unwrap()); + assert_eq!(_20, cast(20i32).unwrap()); + assert_eq!(_20, cast(20i64).unwrap()); + assert_eq!(_20, cast(20f32).unwrap()); + assert_eq!(_20, cast(20f64).unwrap()); }) ) diff --git a/src/libstd/num/strconv.rs b/src/libstd/num/strconv.rs index 1863369fdf7..0f253a26ccf 100644 --- a/src/libstd/num/strconv.rs +++ b/src/libstd/num/strconv.rs @@ -140,7 +140,7 @@ pub fn int_to_str_bytes_common '0' as u8 + i, i => 'a' as u8 + (i - 10), }; @@ -247,7 +247,7 @@ pub fn float_to_str_bytes_common break @@ -322,7 +322,7 @@ pub fn float_to_str_bytes_common+ let _0: T = Zero::zero(); let _1: T = One::one(); - let radix_gen: T = cast(radix as int); + let radix_gen: T = cast(radix as int).unwrap(); let len = buf.len(); @@ -543,9 +543,9 @@ pub fn from_str_bytes_common+ // add/subtract current digit depending on sign if accum_positive { - accum = accum + cast(digit as int); + accum = accum + cast(digit as int).unwrap(); } else { - accum = accum - cast(digit as int); + accum = accum - cast(digit as int).unwrap(); } // Detect overflow by comparing to last value, except @@ -556,11 +556,11 @@ pub fn from_str_bytes_common+ // Detect overflow by reversing the shift-and-add proccess if accum_positive && - (last_accum != ((accum - cast(digit as int))/radix_gen.clone())) { + (last_accum != ((accum - cast(digit as int).unwrap())/radix_gen.clone())) { return NumStrConv::inf(); } if !accum_positive && - (last_accum != ((accum + cast(digit as int))/radix_gen.clone())) { + (last_accum != ((accum + cast(digit as int).unwrap())/radix_gen.clone())) { return NumStrConv::neg_inf(); } } @@ -596,7 +596,7 @@ pub fn from_str_bytes_common+ // Decrease power one order of magnitude power = power / radix_gen; - let digit_t: T = cast(digit); + let digit_t: T = cast(digit).unwrap(); // add/subtract current digit depending on sign if accum_positive { @@ -654,9 +654,9 @@ pub fn from_str_bytes_common+ match exp { Some(exp_pow) => { multiplier = if exp_pow < 0 { - _1 / pow_with_uint::(base, (-exp_pow.to_int()) as uint) + _1 / pow_with_uint::(base, (-exp_pow.to_int().unwrap()) as uint) } else { - pow_with_uint::(base, exp_pow.to_int() as uint) + pow_with_uint::(base, exp_pow.to_int().unwrap() as uint) } } None => return None // invalid exponent -> invalid number diff --git a/src/libstd/prelude.rs b/src/libstd/prelude.rs index 96ade70f007..273a01c1811 100644 --- a/src/libstd/prelude.rs +++ b/src/libstd/prelude.rs @@ -59,7 +59,7 @@ pub use num::{Orderable, Signed, Unsigned, Round}; pub use num::{Algebraic, Trigonometric, Exponential, Hyperbolic}; pub use num::{Integer, Fractional, Real, RealExt}; pub use num::{Bitwise, BitCount, Bounded}; -pub use num::{Primitive, Int, Float, ToStrRadix}; +pub use num::{Primitive, Int, Float, ToStrRadix, ToPrimitive, FromPrimitive}; pub use path::GenericPath; pub use path::Path; pub use path::PosixPath; diff --git a/src/libstd/rand/mod.rs b/src/libstd/rand/mod.rs index cc9e395e739..f143c936e3a 100644 --- a/src/libstd/rand/mod.rs +++ b/src/libstd/rand/mod.rs @@ -314,12 +314,12 @@ pub trait Rng { /// ``` fn gen_integer_range(&mut self, low: T, high: T) -> T { assert!(low < high, "RNG.gen_integer_range called with low >= high"); - let range = (high - low).to_u64(); + let range = (high - low).to_u64().unwrap(); let accept_zone = u64::max_value - u64::max_value % range; loop { let rand = self.gen::(); if rand < accept_zone { - return low + NumCast::from(rand % range); + return low + NumCast::from(rand % range).unwrap(); } } } -- cgit 1.4.1-3-g733a5 From 9de7ad2d8c1729b7b11c6d234fc8ef8ce96809bb Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Tue, 17 Sep 2013 19:28:35 -0700 Subject: std: Swap {To,From}Primitive to use the 64bit as the unimplemented version One downside with this current implementation is that since BigInt's default is now 64 bit, we can convert larger BigInt's to a primitive, however the current implementation on 32 bit architectures does not take advantage of this fact. --- src/libextra/num/bigint.rs | 48 +++++++++++------------ src/libstd/num/num.rs | 68 +++++++++++++++++---------------- src/libsyntax/ext/deriving/primitive.rs | 12 +++--- 3 files changed, 66 insertions(+), 62 deletions(-) (limited to 'src/libstd') diff --git a/src/libextra/num/bigint.rs b/src/libextra/num/bigint.rs index 493bbfa14b9..dd2acdb2e14 100644 --- a/src/libextra/num/bigint.rs +++ b/src/libextra/num/bigint.rs @@ -20,13 +20,13 @@ A `BigInt` is a combination of `BigUint` and `Sign`. #[allow(non_uppercase_statics)]; use std::cmp::{Eq, Ord, TotalEq, TotalOrd, Ordering, Less, Equal, Greater}; -use std::int; use std::num; use std::num::{Zero, One, ToStrRadix, FromStrRadix, Orderable}; use std::num::{ToPrimitive, FromPrimitive}; use std::rand::Rng; use std::str; use std::uint; +use std::{i64, u64}; use std::vec; /** @@ -503,24 +503,24 @@ impl Integer for BigUint { impl ToPrimitive for BigUint { #[inline] - fn to_int(&self) -> Option { + fn to_i64(&self) -> Option { do self.to_uint().and_then |n| { - // If top bit of uint is set, it's too large to convert to + // If top bit of u64 is set, it's too large to convert to // int. if (n >> (2*BigDigit::bits - 1) != 0) { None } else { - Some(n as int) + Some(n as i64) } } } #[inline] - fn to_uint(&self) -> Option { + fn to_u64(&self) -> Option { match self.data.len() { 0 => Some(0), - 1 => Some(self.data[0] as uint), - 2 => Some(BigDigit::to_uint(self.data[1], self.data[0])), + 1 => Some(self.data[0] as u64), + 2 => Some(BigDigit::to_uint(self.data[1], self.data[0]) as u64), _ => None } } @@ -528,17 +528,17 @@ impl ToPrimitive for BigUint { impl FromPrimitive for BigUint { #[inline] - fn from_int(n: int) -> Option { + fn from_i64(n: i64) -> Option { if (n < 0) { Some(Zero::zero()) } else { - FromPrimitive::from_uint(n as uint) + FromPrimitive::from_u64(n as u64) } } #[inline] - fn from_uint(n: uint) -> Option { - let n = match BigDigit::from_uint(n) { + fn from_u64(n: u64) -> Option { + let n = match BigDigit::from_uint(n as uint) { (0, 0) => Zero::zero(), (0, n0) => BigUint::new(~[n0]), (n1, n0) => BigUint::new(~[n0, n1]) @@ -1083,19 +1083,19 @@ impl Integer for BigInt { impl ToPrimitive for BigInt { #[inline] - fn to_int(&self) -> Option { + fn to_i64(&self) -> Option { match self.sign { - Plus => self.data.to_int(), + Plus => self.data.to_i64(), Zero => Some(0), Minus => { - do self.data.to_uint().and_then |n| { - let m: uint = 1 << (2*BigDigit::bits-1); + do self.data.to_u64().and_then |n| { + let m: u64 = 1 << (2*BigDigit::bits-1); if (n > m) { None } else if (n == m) { - Some(int::min_value) + Some(i64::min_value) } else { - Some(-(n as int)) + Some(-(n as i64)) } } } @@ -1103,9 +1103,9 @@ impl ToPrimitive for BigInt { } #[inline] - fn to_uint(&self) -> Option { + fn to_u64(&self) -> Option { match self.sign { - Plus => self.data.to_uint(), + Plus => self.data.to_u64(), Zero => Some(0), Minus => None } @@ -1114,13 +1114,13 @@ impl ToPrimitive for BigInt { impl FromPrimitive for BigInt { #[inline] - fn from_int(n: int) -> Option { + fn from_i64(n: i64) -> Option { if n > 0 { - do FromPrimitive::from_uint(n as uint).and_then |n| { + do FromPrimitive::from_u64(n as u64).and_then |n| { Some(BigInt::from_biguint(Plus, n)) } } else if n < 0 { - do FromPrimitive::from_uint(uint::max_value - (n as uint) + 1).and_then |n| { + do FromPrimitive::from_u64(u64::max_value - (n as u64) + 1).and_then |n| { Some(BigInt::from_biguint(Minus, n)) } } else { @@ -1129,11 +1129,11 @@ impl FromPrimitive for BigInt { } #[inline] - fn from_uint(n: uint) -> Option { + fn from_u64(n: u64) -> Option { if n == 0 { Some(Zero::zero()) } else { - do FromPrimitive::from_uint(n).and_then |n| { + do FromPrimitive::from_u64(n).and_then |n| { Some(BigInt::from_biguint(Plus, n)) } } diff --git a/src/libstd/num/num.rs b/src/libstd/num/num.rs index a8c85184664..fffa9b49699 100644 --- a/src/libstd/num/num.rs +++ b/src/libstd/num/num.rs @@ -351,65 +351,69 @@ pub trait Float: Real /// A generic trait for converting a value to a number. pub trait ToPrimitive { /// Converts the value of `self` to an `int`. - fn to_int(&self) -> Option; + #[inline] + fn to_int(&self) -> Option { + // XXX: Check for range. + self.to_i64().and_then(|x| Some(x as int)) + } /// Converts the value of `self` to an `i8`. #[inline] fn to_i8(&self) -> Option { // XXX: Check for range. - self.to_int().and_then(|x| Some(x as i8)) + self.to_i64().and_then(|x| Some(x as i8)) } /// Converts the value of `self` to an `i16`. #[inline] fn to_i16(&self) -> Option { // XXX: Check for range. - self.to_int().and_then(|x| Some(x as i16)) + self.to_i64().and_then(|x| Some(x as i16)) } /// Converts the value of `self` to an `i32`. #[inline] fn to_i32(&self) -> Option { // XXX: Check for range. - self.to_int().and_then(|x| Some(x as i32)) + self.to_i64().and_then(|x| Some(x as i32)) } /// Converts the value of `self` to an `i64`. + fn to_i64(&self) -> Option; + + /// Converts the value of `self` to an `uint`. #[inline] - fn to_i64(&self) -> Option { + fn to_uint(&self) -> Option { // XXX: Check for range. - self.to_int().and_then(|x| Some(x as i64)) + self.to_u64().and_then(|x| Some(x as uint)) } - /// Converts the value of `self` to an `uint`. - fn to_uint(&self) -> Option; - /// Converts the value of `self` to an `u8`. #[inline] fn to_u8(&self) -> Option { // XXX: Check for range. - self.to_uint().and_then(|x| Some(x as u8)) + self.to_u64().and_then(|x| Some(x as u8)) } /// Converts the value of `self` to an `u16`. #[inline] fn to_u16(&self) -> Option { // XXX: Check for range. - self.to_uint().and_then(|x| Some(x as u16)) + self.to_u64().and_then(|x| Some(x as u16)) } /// Converts the value of `self` to an `u32`. #[inline] fn to_u32(&self) -> Option { // XXX: Check for range. - self.to_uint().and_then(|x| Some(x as u32)) + self.to_u64().and_then(|x| Some(x as u32)) } /// Converts the value of `self` to an `u64`. #[inline] fn to_u64(&self) -> Option { // XXX: Check for range. - self.to_uint().and_then(|x| Some(x as u64)) + self.to_u64().and_then(|x| Some(x as u64)) } /// Converts the value of `self` to an `f32`. @@ -423,7 +427,7 @@ pub trait ToPrimitive { #[inline] fn to_f64(&self) -> Option { // XXX: Check for range. - self.to_float().and_then(|x| Some(x as f64)) + self.to_i64().and_then(|x| Some(x as f64)) } } @@ -467,80 +471,80 @@ impl_to_primitive!(float) pub trait FromPrimitive { /// Convert an `int` to return an optional value of this type. If the /// value cannot be represented by this value, the `None` is returned. - fn from_int(n: int) -> Option; + #[inline] + fn from_int(n: int) -> Option { + FromPrimitive::from_i64(n as i64) + } /// Convert an `i8` to return an optional value of this type. If the /// type cannot be represented by this value, the `None` is returned. #[inline] fn from_i8(n: i8) -> Option { - FromPrimitive::from_int(n as int) + FromPrimitive::from_i64(n as i64) } /// Convert an `i16` to return an optional value of this type. If the /// type cannot be represented by this value, the `None` is returned. #[inline] fn from_i16(n: i16) -> Option { - FromPrimitive::from_int(n as int) + FromPrimitive::from_i64(n as i64) } /// Convert an `i32` to return an optional value of this type. If the /// type cannot be represented by this value, the `None` is returned. #[inline] fn from_i32(n: i32) -> Option { - FromPrimitive::from_int(n as int) + FromPrimitive::from_i64(n as i64) } /// Convert an `i64` to return an optional value of this type. If the /// type cannot be represented by this value, the `None` is returned. - #[inline] - fn from_i64(n: i64) -> Option { - FromPrimitive::from_int(n as int) - } + fn from_i64(n: i64) -> Option; /// Convert an `uint` to return an optional value of this type. If the /// type cannot be represented by this value, the `None` is returned. - fn from_uint(n: uint) -> Option; + #[inline] + fn from_uint(n: uint) -> Option { + FromPrimitive::from_u64(n as u64) + } /// Convert an `u8` to return an optional value of this type. If the /// type cannot be represented by this value, the `None` is returned. #[inline] fn from_u8(n: u8) -> Option { - FromPrimitive::from_uint(n as uint) + FromPrimitive::from_u64(n as u64) } /// Convert an `u16` to return an optional value of this type. If the /// type cannot be represented by this value, the `None` is returned. #[inline] fn from_u16(n: u16) -> Option { - FromPrimitive::from_uint(n as uint) + FromPrimitive::from_u64(n as u64) } /// Convert an `u32` to return an optional value of this type. If the /// type cannot be represented by this value, the `None` is returned. #[inline] fn from_u32(n: u32) -> Option { - FromPrimitive::from_uint(n as uint) + FromPrimitive::from_u64(n as u64) } /// Convert an `u64` to return an optional value of this type. If the /// type cannot be represented by this value, the `None` is returned. - #[inline] - fn from_u64(n: u64) -> Option { - FromPrimitive::from_uint(n as uint) - } + fn from_u64(n: u64) -> Option; /// Convert a `f32` to return an optional value of this type. If the /// type cannot be represented by this value, the `None` is returned. #[inline] fn from_f32(n: f32) -> Option { - FromPrimitive::from_float(n as float) + FromPrimitive::from_f64(n as f64) } /// Convert a `f64` to return an optional value of this type. If the /// type cannot be represented by this value, the `None` is returned. #[inline] fn from_f64(n: f64) -> Option { - FromPrimitive::from_float(n as float) + FromPrimitive::from_i64(n as i64) } } diff --git a/src/libsyntax/ext/deriving/primitive.rs b/src/libsyntax/ext/deriving/primitive.rs index ddf8fc404d4..38c30def1d1 100644 --- a/src/libsyntax/ext/deriving/primitive.rs +++ b/src/libsyntax/ext/deriving/primitive.rs @@ -25,32 +25,32 @@ pub fn expand_deriving_from_primitive(cx: @ExtCtxt, generics: LifetimeBounds::empty(), methods: ~[ MethodDef { - name: "from_int", + name: "from_i64", generics: LifetimeBounds::empty(), explicit_self: None, args: ~[ - Literal(Path::new(~["int"])), + Literal(Path::new(~["i64"])), ], ret_ty: Literal(Path::new_(~["std", "option", "Option"], None, ~[~Self], true)), const_nonmatching: false, - combine_substructure: |c, s, sub| cs_from("int", c, s, sub), + combine_substructure: |c, s, sub| cs_from("i64", c, s, sub), }, MethodDef { - name: "from_uint", + name: "from_u64", generics: LifetimeBounds::empty(), explicit_self: None, args: ~[ - Literal(Path::new(~["uint"])), + Literal(Path::new(~["u64"])), ], ret_ty: Literal(Path::new_(~["std", "option", "Option"], None, ~[~Self], true)), const_nonmatching: false, - combine_substructure: |c, s, sub| cs_from("uint", c, s, sub), + combine_substructure: |c, s, sub| cs_from("u64", c, s, sub), }, ] }; -- cgit 1.4.1-3-g733a5 From cb240197441723fed70e4076d9eba460d8f209ba Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Wed, 25 Sep 2013 20:22:46 -0700 Subject: std: check bounds for ints/uints in {To,From}Primitive --- src/libstd/num/num.rs | 658 +++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 598 insertions(+), 60 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/num/num.rs b/src/libstd/num/num.rs index fffa9b49699..d0a09ac7ef2 100644 --- a/src/libstd/num/num.rs +++ b/src/libstd/num/num.rs @@ -431,41 +431,200 @@ pub trait ToPrimitive { } } -macro_rules! impl_to_primitive( +macro_rules! impl_to_primitive_int_to_int( + ($SrcT:ty, $DstT:ty) => ( + { + if Primitive::bits(None::<$SrcT>) <= Primitive::bits(None::<$DstT>) { + Some(*self as $DstT) + } else { + let n = *self as i64; + let min_value: $DstT = Bounded::min_value(); + let max_value: $DstT = Bounded::max_value(); + if min_value as i64 <= n && n <= max_value as i64 { + Some(*self as $DstT) + } else { + None + } + } + } + ) +) + +macro_rules! impl_to_primitive_int_to_uint( + ($SrcT:ty, $DstT:ty) => ( + { + let zero: $SrcT = Zero::zero(); + let max_value: $DstT = Bounded::max_value(); + if zero <= *self && *self as u64 <= max_value as u64 { + Some(*self as $DstT) + } else { + None + } + } + ) +) + +macro_rules! impl_to_primitive_int( + ($T:ty) => ( + impl ToPrimitive for $T { + #[inline] + fn to_int(&self) -> Option { impl_to_primitive_int_to_int!($T, int) } + #[inline] + fn to_i8(&self) -> Option { impl_to_primitive_int_to_int!($T, i8) } + #[inline] + fn to_i16(&self) -> Option { impl_to_primitive_int_to_int!($T, i16) } + #[inline] + fn to_i32(&self) -> Option { impl_to_primitive_int_to_int!($T, i32) } + #[inline] + fn to_i64(&self) -> Option { impl_to_primitive_int_to_int!($T, i64) } + + #[inline] + fn to_uint(&self) -> Option { impl_to_primitive_int_to_uint!($T, uint) } + #[inline] + fn to_u8(&self) -> Option { impl_to_primitive_int_to_uint!($T, u8) } + #[inline] + fn to_u16(&self) -> Option { impl_to_primitive_int_to_uint!($T, u16) } + #[inline] + fn to_u32(&self) -> Option { impl_to_primitive_int_to_uint!($T, u32) } + #[inline] + fn to_u64(&self) -> Option { impl_to_primitive_int_to_uint!($T, u64) } + + #[inline] + fn to_f32(&self) -> Option { Some(*self as f32) } + #[inline] + fn to_f64(&self) -> Option { Some(*self as f64) } + } + ) +) + +impl_to_primitive_int!(int) +impl_to_primitive_int!(i8) +impl_to_primitive_int!(i16) +impl_to_primitive_int!(i32) +impl_to_primitive_int!(i64) + +macro_rules! impl_to_primitive_uint_to_int( + ($DstT:ty) => ( + { + let max_value: $DstT = Bounded::max_value(); + if *self as u64 <= max_value as u64 { + Some(*self as $DstT) + } else { + None + } + } + ) +) + +macro_rules! impl_to_primitive_uint_to_uint( + ($SrcT:ty, $DstT:ty) => ( + { + if Primitive::bits(None::<$SrcT>) <= Primitive::bits(None::<$DstT>) { + Some(*self as $DstT) + } else { + let zero: $SrcT = Zero::zero(); + let max_value: $DstT = Bounded::max_value(); + if zero <= *self && *self as u64 <= max_value as u64 { + Some(*self as $DstT) + } else { + None + } + } + } + ) +) + +macro_rules! impl_to_primitive_uint( ($T:ty) => ( impl ToPrimitive for $T { - #[inline] fn to_int(&self) -> Option { Some(*self as int) } - #[inline] fn to_i8(&self) -> Option { Some(*self as i8) } - #[inline] fn to_i16(&self) -> Option { Some(*self as i16) } - #[inline] fn to_i32(&self) -> Option { Some(*self as i32) } - #[inline] fn to_i64(&self) -> Option { Some(*self as i64) } - - #[inline] fn to_uint(&self) -> Option { Some(*self as uint) } - #[inline] fn to_u8(&self) -> Option { Some(*self as u8) } - #[inline] fn to_u16(&self) -> Option { Some(*self as u16) } - #[inline] fn to_u32(&self) -> Option { Some(*self as u32) } - #[inline] fn to_u64(&self) -> Option { Some(*self as u64) } - - #[inline] fn to_float(&self) -> Option { Some(*self as float) } - #[inline] fn to_f32(&self) -> Option { Some(*self as f32) } - #[inline] fn to_f64(&self) -> Option { Some(*self as f64) } + #[inline] + fn to_int(&self) -> Option { impl_to_primitive_uint_to_int!(int) } + #[inline] + fn to_i8(&self) -> Option { impl_to_primitive_uint_to_int!(i8) } + #[inline] + fn to_i16(&self) -> Option { impl_to_primitive_uint_to_int!(i16) } + #[inline] + fn to_i32(&self) -> Option { impl_to_primitive_uint_to_int!(i32) } + #[inline] + fn to_i64(&self) -> Option { impl_to_primitive_uint_to_int!(i64) } + + #[inline] + fn to_uint(&self) -> Option { impl_to_primitive_uint_to_uint!($T, uint) } + #[inline] + fn to_u8(&self) -> Option { impl_to_primitive_uint_to_uint!($T, u8) } + #[inline] + fn to_u16(&self) -> Option { impl_to_primitive_uint_to_uint!($T, u16) } + #[inline] + fn to_u32(&self) -> Option { impl_to_primitive_uint_to_uint!($T, u32) } + #[inline] + fn to_u64(&self) -> Option { impl_to_primitive_uint_to_uint!($T, u64) } + + #[inline] + fn to_f32(&self) -> Option { Some(*self as f32) } + #[inline] + fn to_f64(&self) -> Option { Some(*self as f64) } + } + ) +) + +impl_to_primitive_uint!(uint) +impl_to_primitive_uint!(u8) +impl_to_primitive_uint!(u16) +impl_to_primitive_uint!(u32) +impl_to_primitive_uint!(u64) + +macro_rules! impl_to_primitive_float_to_float( + ($SrcT:ty, $DstT:ty) => ( + if Primitive::bits(None::<$SrcT>) <= Primitive::bits(None::<$DstT>) { + Some(*self as $DstT) + } else { + let n = *self as f64; + let min_value: $SrcT = Bounded::min_value(); + let max_value: $SrcT = Bounded::max_value(); + if min_value as f64 <= n && n <= max_value as f64 { + Some(*self as $DstT) + } else { + None + } + } + ) +) + +macro_rules! impl_to_primitive_float( + ($T:ty) => ( + impl ToPrimitive for $T { + #[inline] + fn to_int(&self) -> Option { Some(*self as int) } + #[inline] + fn to_i8(&self) -> Option { Some(*self as i8) } + #[inline] + fn to_i16(&self) -> Option { Some(*self as i16) } + #[inline] + fn to_i32(&self) -> Option { Some(*self as i32) } + #[inline] + fn to_i64(&self) -> Option { Some(*self as i64) } + + #[inline] + fn to_uint(&self) -> Option { Some(*self as uint) } + #[inline] + fn to_u8(&self) -> Option { Some(*self as u8) } + #[inline] + fn to_u16(&self) -> Option { Some(*self as u16) } + #[inline] + fn to_u32(&self) -> Option { Some(*self as u32) } + #[inline] + fn to_u64(&self) -> Option { Some(*self as u64) } + + #[inline] + fn to_f32(&self) -> Option { impl_to_primitive_float_to_float!($T, f32) } + #[inline] + fn to_f64(&self) -> Option { impl_to_primitive_float_to_float!($T, f64) } } ) ) -impl_to_primitive!(u8) -impl_to_primitive!(u16) -impl_to_primitive!(u32) -impl_to_primitive!(u64) -impl_to_primitive!(uint) -impl_to_primitive!(i8) -impl_to_primitive!(i16) -impl_to_primitive!(i32) -impl_to_primitive!(i64) -impl_to_primitive!(int) -impl_to_primitive!(f32) -impl_to_primitive!(f64) -impl_to_primitive!(float) +impl_to_primitive_float!(f32) +impl_to_primitive_float!(f64) /// A generic trait for converting a number to a value. pub trait FromPrimitive { @@ -609,40 +768,38 @@ pub fn from_f64(n: f64) -> Option { } macro_rules! impl_from_primitive( - ($T:ty) => ( + ($T:ty, $to_ty:expr) => ( impl FromPrimitive for $T { - #[inline] fn from_int(n: int) -> Option<$T> { Some(n as $T) } - #[inline] fn from_i8(n: i8) -> Option<$T> { Some(n as $T) } - #[inline] fn from_i16(n: i16) -> Option<$T> { Some(n as $T) } - #[inline] fn from_i32(n: i32) -> Option<$T> { Some(n as $T) } - #[inline] fn from_i64(n: i64) -> Option<$T> { Some(n as $T) } - - #[inline] fn from_uint(n: uint) -> Option<$T> { Some(n as $T) } - #[inline] fn from_u8(n: u8) -> Option<$T> { Some(n as $T) } - #[inline] fn from_u16(n: u16) -> Option<$T> { Some(n as $T) } - #[inline] fn from_u32(n: u32) -> Option<$T> { Some(n as $T) } - #[inline] fn from_u64(n: u64) -> Option<$T> { Some(n as $T) } - - #[inline] fn from_float(n: float) -> Option<$T> { Some(n as $T) } - #[inline] fn from_f32(n: f32) -> Option<$T> { Some(n as $T) } - #[inline] fn from_f64(n: f64) -> Option<$T> { Some(n as $T) } + #[inline] fn from_int(n: int) -> Option<$T> { $to_ty } + #[inline] fn from_i8(n: i8) -> Option<$T> { $to_ty } + #[inline] fn from_i16(n: i16) -> Option<$T> { $to_ty } + #[inline] fn from_i32(n: i32) -> Option<$T> { $to_ty } + #[inline] fn from_i64(n: i64) -> Option<$T> { $to_ty } + + #[inline] fn from_uint(n: uint) -> Option<$T> { $to_ty } + #[inline] fn from_u8(n: u8) -> Option<$T> { $to_ty } + #[inline] fn from_u16(n: u16) -> Option<$T> { $to_ty } + #[inline] fn from_u32(n: u32) -> Option<$T> { $to_ty } + #[inline] fn from_u64(n: u64) -> Option<$T> { $to_ty } + + #[inline] fn from_f32(n: f32) -> Option<$T> { $to_ty } + #[inline] fn from_f64(n: f64) -> Option<$T> { $to_ty } } ) ) -impl_from_primitive!(u8) -impl_from_primitive!(u16) -impl_from_primitive!(u32) -impl_from_primitive!(u64) -impl_from_primitive!(uint) -impl_from_primitive!(i8) -impl_from_primitive!(i16) -impl_from_primitive!(i32) -impl_from_primitive!(i64) -impl_from_primitive!(int) -impl_from_primitive!(f32) -impl_from_primitive!(f64) -impl_from_primitive!(float) +impl_from_primitive!(int, n.to_int()) +impl_from_primitive!(i8, n.to_i8()) +impl_from_primitive!(i16, n.to_i16()) +impl_from_primitive!(i32, n.to_i32()) +impl_from_primitive!(i64, n.to_i64()) +impl_from_primitive!(uint, n.to_uint()) +impl_from_primitive!(u8, n.to_u8()) +impl_from_primitive!(u16, n.to_u16()) +impl_from_primitive!(u32, n.to_u32()) +impl_from_primitive!(u64, n.to_u64()) +impl_from_primitive!(f32, n.to_f32()) +impl_from_primitive!(f64, n.to_f64()) /// Cast from one machine scalar to another /// @@ -820,8 +977,22 @@ pub fn test_num(ten: T, two: T) { #[cfg(test)] mod tests { use prelude::*; - use uint; use super::*; + use int; + use i8; + use i16; + use i32; + use i64; + use int; + use u8; + use u16; + use u32; + use u64; + use uint; + use u8; + use u16; + use u32; + use u64; macro_rules! test_cast_20( ($_20:expr) => ({ @@ -837,7 +1008,6 @@ mod tests { assert_eq!(20i16, _20.to_i16().unwrap()); assert_eq!(20i32, _20.to_i32().unwrap()); assert_eq!(20i64, _20.to_i64().unwrap()); - assert_eq!(20f, _20.to_float().unwrap()); assert_eq!(20f32, _20.to_f32().unwrap()); assert_eq!(20f64, _20.to_f64().unwrap()); @@ -882,6 +1052,374 @@ mod tests { #[test] fn test_f32_cast() { test_cast_20!(20f32) } #[test] fn test_f64_cast() { test_cast_20!(20f64) } + #[test] + fn test_cast_range_int_min() { + assert_eq!(int::min_value.to_int(), Some(int::min_value as int)); + assert_eq!(int::min_value.to_i8(), None); + assert_eq!(int::min_value.to_i16(), None); + // int::min_value.to_i32() is word-size specific + assert_eq!(int::min_value.to_i64(), Some(int::min_value as i64)); + assert_eq!(int::min_value.to_uint(), None); + assert_eq!(int::min_value.to_u8(), None); + assert_eq!(int::min_value.to_u16(), None); + assert_eq!(int::min_value.to_u32(), None); + assert_eq!(int::min_value.to_u64(), None); + + #[cfg(target_word_size = "32")] + fn check_word_size() { + assert_eq!(int::min_value.to_i32(), Some(int::min_value as i32)); + } + + #[cfg(target_word_size = "64")] + fn check_word_size() { + assert_eq!(int::min_value.to_i32(), None); + } + + check_word_size(); + } + + #[test] + fn test_cast_range_i8_min() { + assert_eq!(i8::min_value.to_int(), Some(i8::min_value as int)); + assert_eq!(i8::min_value.to_i8(), Some(i8::min_value as i8)); + assert_eq!(i8::min_value.to_i16(), Some(i8::min_value as i16)); + assert_eq!(i8::min_value.to_i32(), Some(i8::min_value as i32)); + assert_eq!(i8::min_value.to_i64(), Some(i8::min_value as i64)); + assert_eq!(i8::min_value.to_uint(), None); + assert_eq!(i8::min_value.to_u8(), None); + assert_eq!(i8::min_value.to_u16(), None); + assert_eq!(i8::min_value.to_u32(), None); + assert_eq!(i8::min_value.to_u64(), None); + } + + #[test] + fn test_cast_range_i16_min() { + assert_eq!(i16::min_value.to_int(), Some(i16::min_value as int)); + assert_eq!(i16::min_value.to_i8(), None); + assert_eq!(i16::min_value.to_i16(), Some(i16::min_value as i16)); + assert_eq!(i16::min_value.to_i32(), Some(i16::min_value as i32)); + assert_eq!(i16::min_value.to_i64(), Some(i16::min_value as i64)); + assert_eq!(i16::min_value.to_uint(), None); + assert_eq!(i16::min_value.to_u8(), None); + assert_eq!(i16::min_value.to_u16(), None); + assert_eq!(i16::min_value.to_u32(), None); + assert_eq!(i16::min_value.to_u64(), None); + } + + #[test] + fn test_cast_range_i32_min() { + assert_eq!(i32::min_value.to_int(), Some(i32::min_value as int)); + assert_eq!(i32::min_value.to_i8(), None); + assert_eq!(i32::min_value.to_i16(), None); + assert_eq!(i32::min_value.to_i32(), Some(i32::min_value as i32)); + assert_eq!(i32::min_value.to_i64(), Some(i32::min_value as i64)); + assert_eq!(i32::min_value.to_uint(), None); + assert_eq!(i32::min_value.to_u8(), None); + assert_eq!(i32::min_value.to_u16(), None); + assert_eq!(i32::min_value.to_u32(), None); + assert_eq!(i32::min_value.to_u64(), None); + } + + #[test] + fn test_cast_range_i64_min() { + // i64::min_value.to_int() is word-size specific + assert_eq!(i64::min_value.to_i8(), None); + assert_eq!(i64::min_value.to_i16(), None); + assert_eq!(i64::min_value.to_i32(), None); + assert_eq!(i64::min_value.to_i64(), Some(i64::min_value as i64)); + assert_eq!(i64::min_value.to_uint(), None); + assert_eq!(i64::min_value.to_u8(), None); + assert_eq!(i64::min_value.to_u16(), None); + assert_eq!(i64::min_value.to_u32(), None); + assert_eq!(i64::min_value.to_u64(), None); + + #[cfg(target_word_size = "32")] + fn check_word_size() { + assert_eq!(i64::min_value.to_int(), None); + } + + #[cfg(target_word_size = "64")] + fn check_word_size() { + assert_eq!(i64::min_value.to_int(), Some(i64::min_value as int)); + } + + check_word_size(); + } + + #[test] + fn test_cast_range_int_max() { + assert_eq!(int::max_value.to_int(), Some(int::max_value as int)); + assert_eq!(int::max_value.to_i8(), None); + assert_eq!(int::max_value.to_i16(), None); + // int::max_value.to_i32() is word-size specific + assert_eq!(int::max_value.to_i64(), Some(int::max_value as i64)); + assert_eq!(int::max_value.to_u8(), None); + assert_eq!(int::max_value.to_u16(), None); + // int::max_value.to_u32() is word-size specific + assert_eq!(int::max_value.to_u64(), Some(int::max_value as u64)); + + #[cfg(target_word_size = "32")] + fn check_word_size() { + assert_eq!(int::max_value.to_i32(), Some(int::max_value as i32)); + assert_eq!(int::max_value.to_u32(), Some(int::max_value as u32)); + } + + #[cfg(target_word_size = "64")] + fn check_word_size() { + assert_eq!(int::max_value.to_i32(), None); + assert_eq!(int::max_value.to_u32(), None); + } + + check_word_size(); + } + + #[test] + fn test_cast_range_i8_max() { + assert_eq!(i8::max_value.to_int(), Some(i8::max_value as int)); + assert_eq!(i8::max_value.to_i8(), Some(i8::max_value as i8)); + assert_eq!(i8::max_value.to_i16(), Some(i8::max_value as i16)); + assert_eq!(i8::max_value.to_i32(), Some(i8::max_value as i32)); + assert_eq!(i8::max_value.to_i64(), Some(i8::max_value as i64)); + assert_eq!(i8::max_value.to_uint(), Some(i8::max_value as uint)); + assert_eq!(i8::max_value.to_u8(), Some(i8::max_value as u8)); + assert_eq!(i8::max_value.to_u16(), Some(i8::max_value as u16)); + assert_eq!(i8::max_value.to_u32(), Some(i8::max_value as u32)); + assert_eq!(i8::max_value.to_u64(), Some(i8::max_value as u64)); + } + + #[test] + fn test_cast_range_i16_max() { + assert_eq!(i16::max_value.to_int(), Some(i16::max_value as int)); + assert_eq!(i16::max_value.to_i8(), None); + assert_eq!(i16::max_value.to_i16(), Some(i16::max_value as i16)); + assert_eq!(i16::max_value.to_i32(), Some(i16::max_value as i32)); + assert_eq!(i16::max_value.to_i64(), Some(i16::max_value as i64)); + assert_eq!(i16::max_value.to_uint(), Some(i16::max_value as uint)); + assert_eq!(i16::max_value.to_u8(), None); + assert_eq!(i16::max_value.to_u16(), Some(i16::max_value as u16)); + assert_eq!(i16::max_value.to_u32(), Some(i16::max_value as u32)); + assert_eq!(i16::max_value.to_u64(), Some(i16::max_value as u64)); + } + + #[test] + fn test_cast_range_i32_max() { + assert_eq!(i32::max_value.to_int(), Some(i32::max_value as int)); + assert_eq!(i32::max_value.to_i8(), None); + assert_eq!(i32::max_value.to_i16(), None); + assert_eq!(i32::max_value.to_i32(), Some(i32::max_value as i32)); + assert_eq!(i32::max_value.to_i64(), Some(i32::max_value as i64)); + assert_eq!(i32::max_value.to_uint(), Some(i32::max_value as uint)); + assert_eq!(i32::max_value.to_u8(), None); + assert_eq!(i32::max_value.to_u16(), None); + assert_eq!(i32::max_value.to_u32(), Some(i32::max_value as u32)); + assert_eq!(i32::max_value.to_u64(), Some(i32::max_value as u64)); + } + + #[test] + fn test_cast_range_i64_max() { + // i64::max_value.to_int() is word-size specific + assert_eq!(i64::max_value.to_i8(), None); + assert_eq!(i64::max_value.to_i16(), None); + assert_eq!(i64::max_value.to_i32(), None); + assert_eq!(i64::max_value.to_i64(), Some(i64::max_value as i64)); + // i64::max_value.to_uint() is word-size specific + assert_eq!(i64::max_value.to_u8(), None); + assert_eq!(i64::max_value.to_u16(), None); + assert_eq!(i64::max_value.to_u32(), None); + assert_eq!(i64::max_value.to_u64(), Some(i64::max_value as u64)); + + #[cfg(target_word_size = "32")] + fn check_word_size() { + assert_eq!(i64::max_value.to_int(), None); + assert_eq!(i64::max_value.to_uint(), None); + } + + #[cfg(target_word_size = "64")] + fn check_word_size() { + assert_eq!(i64::max_value.to_int(), Some(i64::max_value as int)); + assert_eq!(i64::max_value.to_uint(), Some(i64::max_value as uint)); + } + + check_word_size(); + } + + #[test] + fn test_cast_range_uint_min() { + assert_eq!(uint::min_value.to_int(), Some(uint::min_value as int)); + assert_eq!(uint::min_value.to_i8(), Some(uint::min_value as i8)); + assert_eq!(uint::min_value.to_i16(), Some(uint::min_value as i16)); + assert_eq!(uint::min_value.to_i32(), Some(uint::min_value as i32)); + assert_eq!(uint::min_value.to_i64(), Some(uint::min_value as i64)); + assert_eq!(uint::min_value.to_uint(), Some(uint::min_value as uint)); + assert_eq!(uint::min_value.to_u8(), Some(uint::min_value as u8)); + assert_eq!(uint::min_value.to_u16(), Some(uint::min_value as u16)); + assert_eq!(uint::min_value.to_u32(), Some(uint::min_value as u32)); + assert_eq!(uint::min_value.to_u64(), Some(uint::min_value as u64)); + } + + #[test] + fn test_cast_range_u8_min() { + assert_eq!(u8::min_value.to_int(), Some(u8::min_value as int)); + assert_eq!(u8::min_value.to_i8(), Some(u8::min_value as i8)); + assert_eq!(u8::min_value.to_i16(), Some(u8::min_value as i16)); + assert_eq!(u8::min_value.to_i32(), Some(u8::min_value as i32)); + assert_eq!(u8::min_value.to_i64(), Some(u8::min_value as i64)); + assert_eq!(u8::min_value.to_uint(), Some(u8::min_value as uint)); + assert_eq!(u8::min_value.to_u8(), Some(u8::min_value as u8)); + assert_eq!(u8::min_value.to_u16(), Some(u8::min_value as u16)); + assert_eq!(u8::min_value.to_u32(), Some(u8::min_value as u32)); + assert_eq!(u8::min_value.to_u64(), Some(u8::min_value as u64)); + } + + #[test] + fn test_cast_range_u16_min() { + assert_eq!(u16::min_value.to_int(), Some(u16::min_value as int)); + assert_eq!(u16::min_value.to_i8(), Some(u16::min_value as i8)); + assert_eq!(u16::min_value.to_i16(), Some(u16::min_value as i16)); + assert_eq!(u16::min_value.to_i32(), Some(u16::min_value as i32)); + assert_eq!(u16::min_value.to_i64(), Some(u16::min_value as i64)); + assert_eq!(u16::min_value.to_uint(), Some(u16::min_value as uint)); + assert_eq!(u16::min_value.to_u8(), Some(u16::min_value as u8)); + assert_eq!(u16::min_value.to_u16(), Some(u16::min_value as u16)); + assert_eq!(u16::min_value.to_u32(), Some(u16::min_value as u32)); + assert_eq!(u16::min_value.to_u64(), Some(u16::min_value as u64)); + } + + #[test] + fn test_cast_range_u32_min() { + assert_eq!(u32::min_value.to_int(), Some(u32::min_value as int)); + assert_eq!(u32::min_value.to_i8(), Some(u32::min_value as i8)); + assert_eq!(u32::min_value.to_i16(), Some(u32::min_value as i16)); + assert_eq!(u32::min_value.to_i32(), Some(u32::min_value as i32)); + assert_eq!(u32::min_value.to_i64(), Some(u32::min_value as i64)); + assert_eq!(u32::min_value.to_uint(), Some(u32::min_value as uint)); + assert_eq!(u32::min_value.to_u8(), Some(u32::min_value as u8)); + assert_eq!(u32::min_value.to_u16(), Some(u32::min_value as u16)); + assert_eq!(u32::min_value.to_u32(), Some(u32::min_value as u32)); + assert_eq!(u32::min_value.to_u64(), Some(u32::min_value as u64)); + } + + #[test] + fn test_cast_range_u64_min() { + assert_eq!(u64::min_value.to_int(), Some(u64::min_value as int)); + assert_eq!(u64::min_value.to_i8(), Some(u64::min_value as i8)); + assert_eq!(u64::min_value.to_i16(), Some(u64::min_value as i16)); + assert_eq!(u64::min_value.to_i32(), Some(u64::min_value as i32)); + assert_eq!(u64::min_value.to_i64(), Some(u64::min_value as i64)); + assert_eq!(u64::min_value.to_uint(), Some(u64::min_value as uint)); + assert_eq!(u64::min_value.to_u8(), Some(u64::min_value as u8)); + assert_eq!(u64::min_value.to_u16(), Some(u64::min_value as u16)); + assert_eq!(u64::min_value.to_u32(), Some(u64::min_value as u32)); + assert_eq!(u64::min_value.to_u64(), Some(u64::min_value as u64)); + } + + #[test] + fn test_cast_range_uint_max() { + assert_eq!(uint::max_value.to_int(), None); + assert_eq!(uint::max_value.to_i8(), None); + assert_eq!(uint::max_value.to_i16(), None); + assert_eq!(uint::max_value.to_i32(), None); + // uint::max_value.to_i64() is word-size specific + assert_eq!(uint::max_value.to_u8(), None); + assert_eq!(uint::max_value.to_u16(), None); + // uint::max_value.to_u32() is word-size specific + assert_eq!(uint::max_value.to_u64(), Some(uint::max_value as u64)); + + #[cfg(target_word_size = "32")] + fn check_word_size() { + assert_eq!(uint::max_value.to_u32(), Some(uint::max_value as u32)); + assert_eq!(uint::max_value.to_i64(), Some(uint::max_value as i64)); + } + + #[cfg(target_word_size = "64")] + fn check_word_size() { + assert_eq!(uint::max_value.to_u32(), None); + assert_eq!(uint::max_value.to_i64(), None); + } + + check_word_size(); + } + + #[test] + fn test_cast_range_u8_max() { + assert_eq!(u8::max_value.to_int(), Some(u8::max_value as int)); + assert_eq!(u8::max_value.to_i8(), None); + assert_eq!(u8::max_value.to_i16(), Some(u8::max_value as i16)); + assert_eq!(u8::max_value.to_i32(), Some(u8::max_value as i32)); + assert_eq!(u8::max_value.to_i64(), Some(u8::max_value as i64)); + assert_eq!(u8::max_value.to_uint(), Some(u8::max_value as uint)); + assert_eq!(u8::max_value.to_u8(), Some(u8::max_value as u8)); + assert_eq!(u8::max_value.to_u16(), Some(u8::max_value as u16)); + assert_eq!(u8::max_value.to_u32(), Some(u8::max_value as u32)); + assert_eq!(u8::max_value.to_u64(), Some(u8::max_value as u64)); + } + + #[test] + fn test_cast_range_u16_max() { + assert_eq!(u16::max_value.to_int(), Some(u16::max_value as int)); + assert_eq!(u16::max_value.to_i8(), None); + assert_eq!(u16::max_value.to_i16(), None); + assert_eq!(u16::max_value.to_i32(), Some(u16::max_value as i32)); + assert_eq!(u16::max_value.to_i64(), Some(u16::max_value as i64)); + assert_eq!(u16::max_value.to_uint(), Some(u16::max_value as uint)); + assert_eq!(u16::max_value.to_u8(), None); + assert_eq!(u16::max_value.to_u16(), Some(u16::max_value as u16)); + assert_eq!(u16::max_value.to_u32(), Some(u16::max_value as u32)); + assert_eq!(u16::max_value.to_u64(), Some(u16::max_value as u64)); + } + + #[test] + fn test_cast_range_u32_max() { + // u32::max_value.to_int() is word-size specific + assert_eq!(u32::max_value.to_i8(), None); + assert_eq!(u32::max_value.to_i16(), None); + assert_eq!(u32::max_value.to_i32(), None); + assert_eq!(u32::max_value.to_i64(), Some(u32::max_value as i64)); + assert_eq!(u32::max_value.to_uint(), Some(u32::max_value as uint)); + assert_eq!(u32::max_value.to_u8(), None); + assert_eq!(u32::max_value.to_u16(), None); + assert_eq!(u32::max_value.to_u32(), Some(u32::max_value as u32)); + assert_eq!(u32::max_value.to_u64(), Some(u32::max_value as u64)); + + #[cfg(target_word_size = "32")] + fn check_word_size() { + assert_eq!(u32::max_value.to_int(), None); + } + + #[cfg(target_word_size = "64")] + fn check_word_size() { + assert_eq!(u32::max_value.to_int(), Some(u32::max_value as int)); + } + + check_word_size(); + } + + #[test] + fn test_cast_range_u64_max() { + assert_eq!(u64::max_value.to_int(), None); + assert_eq!(u64::max_value.to_i8(), None); + assert_eq!(u64::max_value.to_i16(), None); + assert_eq!(u64::max_value.to_i32(), None); + assert_eq!(u64::max_value.to_i64(), None); + // u64::max_value.to_uint() is word-size specific + assert_eq!(u64::max_value.to_u8(), None); + assert_eq!(u64::max_value.to_u16(), None); + assert_eq!(u64::max_value.to_u32(), None); + assert_eq!(u64::max_value.to_u64(), Some(u64::max_value as u64)); + + #[cfg(target_word_size = "32")] + fn check_word_size() { + assert_eq!(u64::max_value.to_uint(), None); + } + + #[cfg(target_word_size = "64")] + fn check_word_size() { + assert_eq!(u64::max_value.to_uint(), Some(u64::max_value as uint)); + } + + check_word_size(); + } + #[test] fn test_saturating_add_uint() { use uint::max_value; -- cgit 1.4.1-3-g733a5 From da145b237241345a9b14531d37f290082c4fb5f0 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Thu, 26 Sep 2013 22:15:43 -0700 Subject: std: fix some warnings --- src/libstd/num/num.rs | 5 ----- 1 file changed, 5 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/num/num.rs b/src/libstd/num/num.rs index d0a09ac7ef2..f2160b3735c 100644 --- a/src/libstd/num/num.rs +++ b/src/libstd/num/num.rs @@ -978,7 +978,6 @@ pub fn test_num(ten: T, two: T) { mod tests { use prelude::*; use super::*; - use int; use i8; use i16; use i32; @@ -989,10 +988,6 @@ mod tests { use u32; use u64; use uint; - use u8; - use u16; - use u32; - use u64; macro_rules! test_cast_20( ($_20:expr) => ({ -- cgit 1.4.1-3-g733a5 From 50fde8c024a30d01ed54a2d40eab7399bf1e7a3c Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Fri, 27 Sep 2013 17:09:18 -0700 Subject: std: ToPrimitive's default impls should use `.to_*()` This allows the default methods to be properly range checked. --- src/libstd/num/num.rs | 33 +++++++++++---------------------- 1 file changed, 11 insertions(+), 22 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/num/num.rs b/src/libstd/num/num.rs index f2160b3735c..bccb20de458 100644 --- a/src/libstd/num/num.rs +++ b/src/libstd/num/num.rs @@ -353,29 +353,25 @@ pub trait ToPrimitive { /// Converts the value of `self` to an `int`. #[inline] fn to_int(&self) -> Option { - // XXX: Check for range. - self.to_i64().and_then(|x| Some(x as int)) + self.to_i64().and_then(|x| x.to_int()) } /// Converts the value of `self` to an `i8`. #[inline] fn to_i8(&self) -> Option { - // XXX: Check for range. - self.to_i64().and_then(|x| Some(x as i8)) + self.to_i64().and_then(|x| x.to_i8()) } /// Converts the value of `self` to an `i16`. #[inline] fn to_i16(&self) -> Option { - // XXX: Check for range. - self.to_i64().and_then(|x| Some(x as i16)) + self.to_i64().and_then(|x| x.to_i16()) } /// Converts the value of `self` to an `i32`. #[inline] fn to_i32(&self) -> Option { - // XXX: Check for range. - self.to_i64().and_then(|x| Some(x as i32)) + self.to_i64().and_then(|x| x.to_i32()) } /// Converts the value of `self` to an `i64`. @@ -384,50 +380,43 @@ pub trait ToPrimitive { /// Converts the value of `self` to an `uint`. #[inline] fn to_uint(&self) -> Option { - // XXX: Check for range. - self.to_u64().and_then(|x| Some(x as uint)) + self.to_u64().and_then(|x| x.to_uint()) } /// Converts the value of `self` to an `u8`. #[inline] fn to_u8(&self) -> Option { - // XXX: Check for range. - self.to_u64().and_then(|x| Some(x as u8)) + self.to_u64().and_then(|x| x.to_u8()) } /// Converts the value of `self` to an `u16`. #[inline] fn to_u16(&self) -> Option { - // XXX: Check for range. - self.to_u64().and_then(|x| Some(x as u16)) + self.to_u64().and_then(|x| x.to_u16()) } /// Converts the value of `self` to an `u32`. #[inline] fn to_u32(&self) -> Option { - // XXX: Check for range. - self.to_u64().and_then(|x| Some(x as u32)) + self.to_u64().and_then(|x| x.to_u32()) } /// Converts the value of `self` to an `u64`. #[inline] fn to_u64(&self) -> Option { - // XXX: Check for range. - self.to_u64().and_then(|x| Some(x as u64)) + self.to_u64().and_then(|x| x.to_u64()) } /// Converts the value of `self` to an `f32`. #[inline] fn to_f32(&self) -> Option { - // XXX: Check for range. - self.to_float().and_then(|x| Some(x as f32)) + self.to_f64().and_then(|x| x.to_f32()) } /// Converts the value of `self` to an `f64`. #[inline] fn to_f64(&self) -> Option { - // XXX: Check for range. - self.to_i64().and_then(|x| Some(x as f64)) + self.to_i64().and_then(|x| x.to_f64()) } } -- cgit 1.4.1-3-g733a5 From 41f9deb2ee660cf45bc583171cc7c43a4b3ef4d5 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Fri, 27 Sep 2013 20:41:49 -0700 Subject: std: add Primitive.is_signed --- src/libstd/num/f32.rs | 3 +++ src/libstd/num/f64.rs | 3 +++ src/libstd/num/int_macros.rs | 3 +++ src/libstd/num/num.rs | 1 + src/libstd/num/uint_macros.rs | 3 +++ 5 files changed, 13 insertions(+) (limited to 'src/libstd') diff --git a/src/libstd/num/f32.rs b/src/libstd/num/f32.rs index 41a3d193379..2b4a636e1ad 100644 --- a/src/libstd/num/f32.rs +++ b/src/libstd/num/f32.rs @@ -590,6 +590,9 @@ impl Primitive for f32 { #[inline] fn bytes(_: Option) -> uint { Primitive::bits(Some(0f32)) / 8 } + + #[inline] + fn is_signed(_: Option) -> bool { true } } impl Float for f32 { diff --git a/src/libstd/num/f64.rs b/src/libstd/num/f64.rs index 772596d15fb..d4442e5b34f 100644 --- a/src/libstd/num/f64.rs +++ b/src/libstd/num/f64.rs @@ -638,6 +638,9 @@ impl Primitive for f64 { #[inline] fn bytes(_: Option) -> uint { Primitive::bits(Some(0f64)) / 8 } + + #[inline] + fn is_signed(_: Option) -> bool { true } } impl Float for f64 { diff --git a/src/libstd/num/int_macros.rs b/src/libstd/num/int_macros.rs index 1070e8e592f..7fae567809b 100644 --- a/src/libstd/num/int_macros.rs +++ b/src/libstd/num/int_macros.rs @@ -380,6 +380,9 @@ impl Primitive for $T { #[inline] fn bytes(_: Option<$T>) -> uint { bits / 8 } + + #[inline] + fn is_signed(_: Option<$T>) -> bool { true } } // String conversion functions and impl str -> num diff --git a/src/libstd/num/num.rs b/src/libstd/num/num.rs index bccb20de458..fde1928f4a3 100644 --- a/src/libstd/num/num.rs +++ b/src/libstd/num/num.rs @@ -286,6 +286,7 @@ pub trait Primitive: Clone // FIXME (#8888): Removing `unused_self` requires #8888 to be fixed. fn bits(unused_self: Option) -> uint; fn bytes(unused_self: Option) -> uint; + fn is_signed(unused_self: Option) -> bool; } /// A collection of traits relevant to primitive signed and unsigned integers diff --git a/src/libstd/num/uint_macros.rs b/src/libstd/num/uint_macros.rs index 45280482b87..f52feced67c 100644 --- a/src/libstd/num/uint_macros.rs +++ b/src/libstd/num/uint_macros.rs @@ -306,6 +306,9 @@ impl Primitive for $T { #[inline] fn bytes(_: Option<$T>) -> uint { bits / 8 } + + #[inline] + fn is_signed(_: Option<$T>) -> bool { false } } impl BitCount for $T { -- cgit 1.4.1-3-g733a5