diff --git a/doc/rust.md b/doc/rust.md index 2a1b30bd7fa..56d116804f5 100644 --- a/doc/rust.md +++ b/doc/rust.md @@ -1775,6 +1775,7 @@ Supported traits for `deriving` are: `obj.to_str()` has similar output as `fmt!("%?", obj)`, but it differs in that each constituent field of the type must also implement `ToStr` and will have `field.to_str()` invoked to build up the result. +* `FromPrimitive`, to create an instance from a numeric primitve. ### Stability One can indicate the stability of an API using the following attributes: diff --git a/src/libextra/num/bigint.rs b/src/libextra/num/bigint.rs index 48fcd972c3c..8604674ea12 100644 --- a/src/libextra/num/bigint.rs +++ b/src/libextra/num/bigint.rs @@ -20,12 +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::{IntConvertible, Zero, One, ToStrRadix, FromStrRadix, Orderable}; +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; /** @@ -500,18 +501,152 @@ impl Integer for BigUint { fn is_odd(&self) -> bool { !self.is_even() } } -impl IntConvertible for BigUint { +impl ToPrimitive for BigUint { #[inline] - fn to_int(&self) -> int { - self.to_int_opt().expect("BigUint conversion would overflow int") + fn to_i64(&self) -> Option { + do self.to_u64().and_then |n| { + // If top bit of u64 is set, it's too large to convert to i64. + if n >> 63 == 0 { + Some(n as i64) + } else { + None + } + } } + #[cfg(target_word_size = "32")] #[inline] - fn from_int(n: int) -> BigUint { - if (n < 0) { Zero::zero() } else { BigUint::from_uint(n as uint) } + fn to_u64(&self) -> Option { + match self.data { + [] => { + Some(0) + } + [n0] => { + Some(n0 as u64) + } + [n0, n1] => { + Some(BigDigit::to_uint(n1, n0) as u64) + } + [n0, n1, n2] => { + let n_lo = BigDigit::to_uint(n1, n0) as u64; + let n_hi = n2 as u64; + Some((n_hi << 32) + n_lo) + } + [n0, n1, n2, n3] => { + let n_lo = BigDigit::to_uint(n1, n0) as u64; + let n_hi = BigDigit::to_uint(n3, n2) as u64; + Some((n_hi << 32) + n_lo) + } + _ => None + } + } + + #[cfg(target_word_size = "64")] + #[inline] + fn to_u64(&self) -> Option { + match self.data { + [] => { + Some(0) + } + [n0] => { + Some(n0 as u64) + } + [n0, n1] => { + Some(BigDigit::to_uint(n1, n0) as u64) + } + _ => None + } } } +impl FromPrimitive for BigUint { + #[inline] + fn from_i64(n: i64) -> Option { + if (n > 0) { + FromPrimitive::from_u64(n as u64) + } else if (n == 0) { + Some(Zero::zero()) + } else { + None + } + } + + #[cfg(target_word_size = "32")] + #[inline] + fn from_u64(n: u64) -> Option { + let n_lo = (n & 0x0000_0000_FFFF_FFFF) as uint; + let n_hi = (n >> 32) as uint; + + let n = match (BigDigit::from_uint(n_hi), BigDigit::from_uint(n_lo)) { + ((0, 0), (0, 0)) => Zero::zero(), + ((0, 0), (0, n0)) => BigUint::new(~[n0]), + ((0, 0), (n1, n0)) => BigUint::new(~[n0, n1]), + ((0, n2), (n1, n0)) => BigUint::new(~[n0, n1, n2]), + ((n3, n2), (n1, n0)) => BigUint::new(~[n0, n1, n2, n3]), + }; + Some(n) + } + + #[cfg(target_word_size = "64")] + #[inline] + 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]) + }; + Some(n) + } +} + +/// A generic trait for converting a value to a `BigUint`. +pub trait ToBigUint { + /// Converts the value of `self` to a `BigUint`. + fn to_biguint(&self) -> Option; +} + +impl ToBigUint for BigInt { + #[inline] + fn to_biguint(&self) -> Option { + if self.sign == Plus { + Some(self.data.clone()) + } else if self.sign == Zero { + Some(Zero::zero()) + } else { + None + } + } +} + +impl ToBigUint for BigUint { + #[inline] + fn to_biguint(&self) -> Option { + Some(self.clone()) + } +} + +macro_rules! impl_to_biguint( + ($T:ty, $from_ty:path) => { + impl ToBigUint for $T { + #[inline] + fn to_biguint(&self) -> Option { + $from_ty(*self) + } + } + } +) + +impl_to_biguint!(int, FromPrimitive::from_int) +impl_to_biguint!(i8, FromPrimitive::from_i8) +impl_to_biguint!(i16, FromPrimitive::from_i16) +impl_to_biguint!(i32, FromPrimitive::from_i32) +impl_to_biguint!(i64, FromPrimitive::from_i64) +impl_to_biguint!(uint, FromPrimitive::from_uint) +impl_to_biguint!(u8, FromPrimitive::from_u8) +impl_to_biguint!(u16, FromPrimitive::from_u16) +impl_to_biguint!(u32, FromPrimitive::from_u32) +impl_to_biguint!(u64, FromPrimitive::from_u64) + impl ToStrRadix for BigUint { fn to_str_radix(&self, radix: uint) -> ~str { assert!(1 < radix && radix <= 16); @@ -522,16 +657,16 @@ impl ToStrRadix for BigUint { return fill_concat(convert_base((*self).clone(), base), radix, max_len); fn convert_base(n: BigUint, base: uint) -> ~[BigDigit] { - let divider = BigUint::from_uint(base); + let divider = FromPrimitive::from_uint(base).unwrap(); let mut result = ~[]; let mut m = n; while m > divider { let (d, m0) = m.div_mod_floor(÷r); - result.push(m0.to_uint() as BigDigit); + result.push(m0.to_uint().unwrap() as BigDigit); m = d; } if !m.is_zero() { - result.push(m.to_uint() as BigDigit); + result.push(m.to_uint().unwrap() as BigDigit); } return result; } @@ -571,16 +706,6 @@ impl BigUint { return BigUint { data: v }; } - /// Creates and initializes a `BigUint`. - #[inline] - pub fn from_uint(n: uint) -> BigUint { - match BigDigit::from_uint(n) { - (0, 0) => Zero::zero(), - (0, n0) => BigUint::new(~[n0]), - (n1, n0) => BigUint::new(~[n0, n1]) - } - } - /// Creates and initializes a `BigUint`. #[inline] pub fn from_slice(slice: &[BigDigit]) -> BigUint { @@ -588,10 +713,12 @@ impl BigUint { } /// Creates and initializes a `BigUint`. - pub fn parse_bytes(buf: &[u8], radix: uint) - -> Option { + pub fn parse_bytes(buf: &[u8], radix: uint) -> Option { let (base, unit_len) = get_radix_base(radix); - let base_num: BigUint = BigUint::from_uint(base); + let base_num = match FromPrimitive::from_uint(base) { + Some(base_num) => base_num, + None => { return None; } + }; let mut end = buf.len(); let mut n: BigUint = Zero::zero(); @@ -599,10 +726,19 @@ impl BigUint { loop { let start = num::max(end, unit_len) - unit_len; match uint::parse_bytes(buf.slice(start, end), radix) { - // FIXME(#6102): Assignment operator for BigInt causes ICE - // Some(d) => n += BigUint::from_uint(d) * power, - Some(d) => n = n + BigUint::from_uint(d) * power, - None => return None + Some(d) => { + let d: Option = FromPrimitive::from_uint(d); + match d { + Some(d) => { + // FIXME(#6102): Assignment operator for BigInt + // causes ICE: + // n += d * power; + n = n + d * power; + } + None => { return None; } + } + } + None => { return None; } } if end <= unit_len { return Some(n); @@ -614,44 +750,6 @@ impl BigUint { } } - - /// Converts this `BigUint` into a `uint`, failing if the conversion - /// would overflow. - #[inline] - pub fn to_uint(&self) -> uint { - self.to_uint_opt().expect("BigUint conversion would overflow uint") - } - - /// Converts this `BigUint` into a `uint`, unless it would overflow. - #[inline] - pub fn to_uint_opt(&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])), - _ => None - } - } - - /// Converts this `BigUint` into an `int`, unless it would overflow. - pub fn to_int_opt(&self) -> Option { - self.to_uint_opt().and_then(|n| { - // If top bit of uint is set, it's too large to convert to - // int. - if (n >> (2*BigDigit::bits - 1) != 0) { - None - } else { - Some(n as int) - } - }) - } - - /// Converts this `BigUint` into a `BigInt`. - #[inline] - pub fn to_bigint(&self) -> BigInt { - BigInt::from_biguint(Plus, self.clone()) - } - #[inline] fn shl_unit(&self, n_unit: uint) -> BigUint { if n_unit == 0 || self.is_zero() { return (*self).clone(); } @@ -706,30 +804,6 @@ impl BigUint { } } -#[cfg(target_word_size = "64")] -#[inline] -fn get_radix_base(radix: uint) -> (uint, uint) { - assert!(1 < radix && radix <= 16); - match radix { - 2 => (4294967296, 32), - 3 => (3486784401, 20), - 4 => (4294967296, 16), - 5 => (1220703125, 13), - 6 => (2176782336, 12), - 7 => (1977326743, 11), - 8 => (1073741824, 10), - 9 => (3486784401, 10), - 10 => (1000000000, 9), - 11 => (2357947691, 9), - 12 => (429981696, 8), - 13 => (815730721, 8), - 14 => (1475789056, 8), - 15 => (2562890625, 8), - 16 => (4294967296, 8), - _ => fail2!() - } -} - #[cfg(target_word_size = "32")] #[inline] fn get_radix_base(radix: uint) -> (uint, uint) { @@ -754,6 +828,30 @@ fn get_radix_base(radix: uint) -> (uint, uint) { } } +#[cfg(target_word_size = "64")] +#[inline] +fn get_radix_base(radix: uint) -> (uint, uint) { + assert!(1 < radix && radix <= 16); + match radix { + 2 => (4294967296, 32), + 3 => (3486784401, 20), + 4 => (4294967296, 16), + 5 => (1220703125, 13), + 6 => (2176782336, 12), + 7 => (1977326743, 11), + 8 => (1073741824, 10), + 9 => (3486784401, 10), + 10 => (1000000000, 9), + 11 => (2357947691, 9), + 12 => (429981696, 8), + 13 => (815730721, 8), + 14 => (1475789056, 8), + 15 => (2562890625, 8), + 16 => (4294967296, 8), + _ => fail2!() + } +} + /// A Sign is a `BigInt`'s composing element. #[deriving(Eq, Clone)] pub enum Sign { Minus, Zero, Plus } @@ -1077,26 +1175,111 @@ impl Integer for BigInt { fn is_odd(&self) -> bool { self.data.is_odd() } } -impl IntConvertible for BigInt { +impl ToPrimitive for BigInt { #[inline] - fn to_int(&self) -> int { - self.to_int_opt().expect("BigInt conversion would overflow int") + fn to_i64(&self) -> Option { + match self.sign { + Plus => self.data.to_i64(), + Zero => Some(0), + Minus => { + do self.data.to_u64().and_then |n| { + let m: u64 = 1 << 63; + if n < m { + Some(-(n as i64)) + } else if n == m { + Some(i64::min_value) + } else { + None + } + } + } + } } #[inline] - fn from_int(n: int) -> BigInt { - if n > 0 { - return BigInt::from_biguint(Plus, BigUint::from_uint(n as uint)); + fn to_u64(&self) -> Option { + match self.sign { + Plus => self.data.to_u64(), + Zero => Some(0), + Minus => None } - if n < 0 { - return BigInt::from_biguint( - Minus, BigUint::from_uint(uint::max_value - (n as uint) + 1) - ); - } - return Zero::zero(); } } +impl FromPrimitive for BigInt { + #[inline] + fn from_i64(n: i64) -> Option { + if n > 0 { + do FromPrimitive::from_u64(n as u64).and_then |n| { + Some(BigInt::from_biguint(Plus, n)) + } + } else if n < 0 { + do FromPrimitive::from_u64(u64::max_value - (n as u64) + 1).and_then |n| { + Some(BigInt::from_biguint(Minus, n)) + } + } else { + Some(Zero::zero()) + } + } + + #[inline] + fn from_u64(n: u64) -> Option { + if n == 0 { + Some(Zero::zero()) + } else { + do FromPrimitive::from_u64(n).and_then |n| { + Some(BigInt::from_biguint(Plus, n)) + } + } + } +} + +/// A generic trait for converting a value to a `BigInt`. +pub trait ToBigInt { + /// Converts the value of `self` to a `BigInt`. + fn to_bigint(&self) -> Option; +} + +impl ToBigInt for BigInt { + #[inline] + fn to_bigint(&self) -> Option { + Some(self.clone()) + } +} + +impl ToBigInt for BigUint { + #[inline] + fn to_bigint(&self) -> Option { + if self.is_zero() { + Some(Zero::zero()) + } else { + Some(BigInt { sign: Plus, data: self.clone() }) + } + } +} + +macro_rules! impl_to_bigint( + ($T:ty, $from_ty:path) => { + impl ToBigInt for $T { + #[inline] + fn to_bigint(&self) -> Option { + $from_ty(*self) + } + } + } +) + +impl_to_bigint!(int, FromPrimitive::from_int) +impl_to_bigint!(i8, FromPrimitive::from_i8) +impl_to_bigint!(i16, FromPrimitive::from_i16) +impl_to_bigint!(i32, FromPrimitive::from_i32) +impl_to_bigint!(i64, FromPrimitive::from_i64) +impl_to_bigint!(uint, FromPrimitive::from_uint) +impl_to_bigint!(u8, FromPrimitive::from_u8) +impl_to_bigint!(u16, FromPrimitive::from_u16) +impl_to_bigint!(u32, FromPrimitive::from_u32) +impl_to_bigint!(u64, FromPrimitive::from_u64) + impl ToStrRadix for BigInt { #[inline] fn to_str_radix(&self, radix: uint) -> ~str { @@ -1196,8 +1379,8 @@ impl RandBigInt for R { ubound: &BigInt) -> BigInt { assert!(*lbound < *ubound); - let delta = (*ubound - *lbound).to_biguint(); - return *lbound + self.gen_biguint_below(&delta).to_bigint(); + let delta = (*ubound - *lbound).to_biguint().unwrap(); + return *lbound + self.gen_biguint_below(&delta).to_bigint().unwrap(); } } @@ -1217,13 +1400,6 @@ impl BigInt { return BigInt { sign: sign, data: data }; } - /// Creates and initializes a `BigInt`. - #[inline] - pub fn from_uint(n: uint) -> BigInt { - if n == 0 { return Zero::zero(); } - return BigInt::from_biguint(Plus, BigUint::from_uint(n)); - } - /// Creates and initializes a `BigInt`. #[inline] pub fn from_slice(sign: Sign, slice: &[BigDigit]) -> BigInt { @@ -1244,51 +1420,9 @@ impl BigInt { .map_move(|bu| BigInt::from_biguint(sign, bu)); } - /// Converts this `BigInt` into a `uint`, failing if the conversion - /// would overflow. - #[inline] - pub fn to_uint(&self) -> uint { - self.to_uint_opt().expect("BigInt conversion would overflow uint") - } - - /// Converts this `BigInt` into a `uint`, unless it would overflow. - #[inline] - pub fn to_uint_opt(&self) -> Option { - match self.sign { - Plus => self.data.to_uint_opt(), - Zero => Some(0), - Minus => None - } - } - - /// Converts this `BigInt` into an `int`, unless it would overflow. - pub fn to_int_opt(&self) -> Option { - match self.sign { - Plus => self.data.to_int_opt(), - Zero => Some(0), - Minus => self.data.to_uint_opt().and_then(|n| { - let m: uint = 1 << (2*BigDigit::bits-1); - if (n > m) { - None - } else if (n == m) { - Some(int::min_value) - } else { - Some(-(n as int)) - } - }) - } - } - - /// Converts this `BigInt` into a `BigUint`, failing if BigInt is - /// negative. - #[inline] - pub fn to_biguint(&self) -> BigUint { - self.to_biguint_opt().expect("negative BigInt cannot convert to BigUint") - } - /// Converts this `BigInt` into a `BigUint`, if it's not negative. #[inline] - pub fn to_biguint_opt(&self) -> Option { + pub fn to_biguint(&self) -> Option { match self.sign { Plus => Some(self.data.clone()), Zero => Some(Zero::zero()), @@ -1299,15 +1433,15 @@ impl BigInt { #[cfg(test)] mod biguint_tests { - use super::*; use std::cmp::{Less, Equal, Greater}; - use std::int; - use std::num::{IntConvertible, Zero, One, FromStrRadix}; + use std::i64; + use std::num::{Zero, One, FromStrRadix}; + use std::num::{ToPrimitive, FromPrimitive}; use std::rand::{task_rng}; use std::str; - use std::uint; + use std::u64; use std::vec; #[test] @@ -1479,49 +1613,117 @@ mod biguint_tests { "88887777666655554444333322221111"); } + #[cfg(target_word_size = "32")] #[test] - fn test_convert_int() { - fn check(v: ~[BigDigit], i: int) { - let b = BigUint::new(v); - assert!(b == IntConvertible::from_int(i)); - assert!(b.to_int() == i); + fn test_convert_i64() { + fn check(b1: BigUint, i: i64) { + let b2: BigUint = FromPrimitive::from_i64(i).unwrap(); + assert!(b1 == b2); + assert!(b1.to_i64().unwrap() == i); } - check(~[], 0); - check(~[1], 1); - check(~[-1], (uint::max_value >> BigDigit::bits) as int); - check(~[ 0, 1], ((uint::max_value >> BigDigit::bits) + 1) as int); - check(~[-1, -1 >> 1], int::max_value); + check(Zero::zero(), 0); + check(One::one(), 1); + check(i64::max_value.to_biguint().unwrap(), i64::max_value); - assert_eq!(BigUint::new(~[0, -1]).to_int_opt(), None); - assert_eq!(BigUint::new(~[0, 0, 1]).to_int_opt(), None); - assert_eq!(BigUint::new(~[0, 0, -1]).to_int_opt(), None); + check(BigUint::new(~[ ]), 0); + check(BigUint::new(~[ 1 ]), (1 << (0*BigDigit::bits))); + check(BigUint::new(~[-1 ]), (1 << (1*BigDigit::bits)) - 1); + check(BigUint::new(~[ 0, 1 ]), (1 << (1*BigDigit::bits))); + check(BigUint::new(~[-1, -1 ]), (1 << (2*BigDigit::bits)) - 1); + check(BigUint::new(~[ 0, 0, 1 ]), (1 << (2*BigDigit::bits))); + check(BigUint::new(~[-1, -1, -1 ]), (1 << (3*BigDigit::bits)) - 1); + check(BigUint::new(~[ 0, 0, 0, 1 ]), (1 << (3*BigDigit::bits))); + check(BigUint::new(~[-1, -1, -1, -1 >> 1]), i64::max_value); + + assert_eq!(i64::min_value.to_biguint(), None); + assert_eq!(BigUint::new(~[-1, -1, -1, -1 ]).to_i64(), None); + assert_eq!(BigUint::new(~[ 0, 0, 0, 0, 1]).to_i64(), None); + assert_eq!(BigUint::new(~[-1, -1, -1, -1, -1]).to_i64(), None); } + #[cfg(target_word_size = "64")] #[test] - fn test_convert_uint() { - fn check(v: ~[BigDigit], u: uint) { - let b = BigUint::new(v); - assert!(b == BigUint::from_uint(u)); - assert!(b.to_uint() == u); + fn test_convert_i64() { + fn check(b1: BigUint, i: i64) { + let b2: BigUint = FromPrimitive::from_i64(i).unwrap(); + assert!(b1 == b2); + assert!(b1.to_i64().unwrap() == i); } - check(~[], 0); - check(~[ 1], 1); - check(~[-1], uint::max_value >> BigDigit::bits); - check(~[ 0, 1], (uint::max_value >> BigDigit::bits) + 1); - check(~[ 0, -1], uint::max_value << BigDigit::bits); - check(~[-1, -1], uint::max_value); + check(Zero::zero(), 0); + check(One::one(), 1); + check(i64::max_value.to_biguint().unwrap(), i64::max_value); - assert_eq!(BigUint::new(~[0, 0, 1]).to_uint_opt(), None); - assert_eq!(BigUint::new(~[0, 0, -1]).to_uint_opt(), None); + check(BigUint::new(~[ ]), 0); + check(BigUint::new(~[ 1 ]), (1 << (0*BigDigit::bits))); + check(BigUint::new(~[-1 ]), (1 << (1*BigDigit::bits)) - 1); + check(BigUint::new(~[ 0, 1 ]), (1 << (1*BigDigit::bits))); + check(BigUint::new(~[-1, -1 >> 1]), i64::max_value); + + assert_eq!(i64::min_value.to_biguint(), None); + assert_eq!(BigUint::new(~[-1, -1 ]).to_i64(), None); + assert_eq!(BigUint::new(~[ 0, 0, 1]).to_i64(), None); + assert_eq!(BigUint::new(~[-1, -1, -1]).to_i64(), None); + } + + #[cfg(target_word_size = "32")] + #[test] + fn test_convert_u64() { + fn check(b1: BigUint, u: u64) { + let b2: BigUint = FromPrimitive::from_u64(u).unwrap(); + assert!(b1 == b2); + assert!(b1.to_u64().unwrap() == u); + } + + check(Zero::zero(), 0); + check(One::one(), 1); + check(u64::min_value.to_biguint().unwrap(), u64::min_value); + check(u64::max_value.to_biguint().unwrap(), u64::max_value); + + check(BigUint::new(~[ ]), 0); + check(BigUint::new(~[ 1 ]), (1 << (0*BigDigit::bits))); + check(BigUint::new(~[-1 ]), (1 << (1*BigDigit::bits)) - 1); + check(BigUint::new(~[ 0, 1 ]), (1 << (1*BigDigit::bits))); + check(BigUint::new(~[-1, -1 ]), (1 << (2*BigDigit::bits)) - 1); + check(BigUint::new(~[ 0, 0, 1 ]), (1 << (2*BigDigit::bits))); + check(BigUint::new(~[-1, -1, -1 ]), (1 << (3*BigDigit::bits)) - 1); + check(BigUint::new(~[ 0, 0, 0, 1]), (1 << (3*BigDigit::bits))); + check(BigUint::new(~[-1, -1, -1, -1]), u64::max_value); + + assert_eq!(BigUint::new(~[ 0, 0, 0, 0, 1]).to_u64(), None); + assert_eq!(BigUint::new(~[-1, -1, -1, -1, -1]).to_u64(), None); + } + + #[cfg(target_word_size = "64")] + #[test] + fn test_convert_u64() { + fn check(b1: BigUint, u: u64) { + let b2: BigUint = FromPrimitive::from_u64(u).unwrap(); + assert!(b1 == b2); + assert!(b1.to_u64().unwrap() == u); + } + + check(Zero::zero(), 0); + check(One::one(), 1); + check(u64::min_value.to_biguint().unwrap(), u64::min_value); + check(u64::max_value.to_biguint().unwrap(), u64::max_value); + + check(BigUint::new(~[ ]), 0); + check(BigUint::new(~[ 1 ]), (1 << (0*BigDigit::bits))); + check(BigUint::new(~[-1 ]), (1 << (1*BigDigit::bits)) - 1); + check(BigUint::new(~[ 0, 1]), (1 << (1*BigDigit::bits))); + check(BigUint::new(~[-1, -1]), u64::max_value); + + assert_eq!(BigUint::new(~[ 0, 0, 1]).to_u64(), None); + assert_eq!(BigUint::new(~[-1, -1, -1]).to_u64(), None); } #[test] fn test_convert_to_bigint() { fn check(n: BigUint, ans: BigInt) { - assert_eq!(n.to_bigint(), ans); - assert_eq!(n.to_bigint().to_biguint(), n); + assert_eq!(n.to_bigint().unwrap(), ans); + assert_eq!(n.to_bigint().unwrap().to_biguint().unwrap(), n); } check(Zero::zero(), Zero::zero()); check(BigUint::new(~[1,2,3]), @@ -1660,9 +1862,9 @@ mod biguint_tests { #[test] fn test_gcd() { fn check(a: uint, b: uint, c: uint) { - let big_a = BigUint::from_uint(a); - let big_b = BigUint::from_uint(b); - let big_c = BigUint::from_uint(c); + let big_a: BigUint = FromPrimitive::from_uint(a).unwrap(); + let big_b: BigUint = FromPrimitive::from_uint(b).unwrap(); + let big_c: BigUint = FromPrimitive::from_uint(c).unwrap(); assert_eq!(big_a.gcd(&big_b), big_c); } @@ -1677,9 +1879,9 @@ mod biguint_tests { #[test] fn test_lcm() { fn check(a: uint, b: uint, c: uint) { - let big_a = BigUint::from_uint(a); - let big_b = BigUint::from_uint(b); - let big_c = BigUint::from_uint(c); + let big_a: BigUint = FromPrimitive::from_uint(a).unwrap(); + let big_b: BigUint = FromPrimitive::from_uint(b).unwrap(); + let big_c: BigUint = FromPrimitive::from_uint(c).unwrap(); assert_eq!(big_a.lcm(&big_b), big_c); } @@ -1694,20 +1896,18 @@ mod biguint_tests { #[test] fn test_is_even() { - let one: Option = FromStr::from_str("1"); - let two: Option = FromStr::from_str("2"); - let thousand: Option = FromStr::from_str("1000"); - let big: Option = - FromStr::from_str("1000000000000000000000"); - let bigger: Option = - FromStr::from_str("1000000000000000000001"); - assert!(one.unwrap().is_odd()); - assert!(two.unwrap().is_even()); - assert!(thousand.unwrap().is_even()); - assert!(big.unwrap().is_even()); - assert!(bigger.unwrap().is_odd()); - assert!((BigUint::from_uint(1) << 64).is_even()); - assert!(((BigUint::from_uint(1) << 64) + BigUint::from_uint(1)).is_odd()); + let one: BigUint = FromStr::from_str("1").unwrap(); + let two: BigUint = FromStr::from_str("2").unwrap(); + let thousand: BigUint = FromStr::from_str("1000").unwrap(); + let big: BigUint = FromStr::from_str("1000000000000000000000").unwrap(); + let bigger: BigUint = FromStr::from_str("1000000000000000000001").unwrap(); + assert!(one.is_odd()); + assert!(two.is_even()); + assert!(thousand.is_even()); + assert!(big.is_even()); + assert!(bigger.is_odd()); + assert!((one << 64).is_even()); + assert!(((one << 64) + one).is_odd()); } fn to_str_pairs() -> ~[ (BigUint, ~[(uint, ~str)]) ] { @@ -1805,8 +2005,8 @@ mod biguint_tests { let mut f: BigUint = One::one(); for i in range(2, n + 1) { // FIXME(#6102): Assignment operator for BigInt causes ICE - // f *= BigUint::from_uint(i); - f = f * BigUint::from_uint(i); + // f *= FromPrimitive::from_uint(i); + f = f * FromPrimitive::from_uint(i).unwrap(); } return f; } @@ -1828,9 +2028,12 @@ mod biguint_tests { #[test] fn test_bits() { assert_eq!(BigUint::new(~[0,0,0,0]).bits(), 0); - assert_eq!(BigUint::from_uint(0).bits(), 0); - assert_eq!(BigUint::from_uint(1).bits(), 1); - assert_eq!(BigUint::from_uint(3).bits(), 2); + let n: BigUint = FromPrimitive::from_uint(0).unwrap(); + assert_eq!(n.bits(), 0); + let n: BigUint = FromPrimitive::from_uint(1).unwrap(); + assert_eq!(n.bits(), 1); + let n: BigUint = FromPrimitive::from_uint(3).unwrap(); + assert_eq!(n.bits(), 2); let n: BigUint = FromStrRadix::from_str_radix("4000000000", 16).unwrap(); assert_eq!(n.bits(), 39); let one: BigUint = One::one(); @@ -1849,13 +2052,13 @@ mod biguint_tests { let mut rng = task_rng(); do 10.times { - assert_eq!(rng.gen_bigint_range(&BigInt::from_uint(236), - &BigInt::from_uint(237)), - BigInt::from_uint(236)); + assert_eq!(rng.gen_bigint_range(&FromPrimitive::from_uint(236).unwrap(), + &FromPrimitive::from_uint(237).unwrap()), + FromPrimitive::from_uint(236).unwrap()); } - let l = BigUint::from_uint(403469000 + 2352); - let u = BigUint::from_uint(403469000 + 3513); + let l = FromPrimitive::from_uint(403469000 + 2352).unwrap(); + let u = FromPrimitive::from_uint(403469000 + 3513).unwrap(); do 1000.times { let n: BigUint = rng.gen_biguint_below(&u); assert!(n < u); @@ -1869,16 +2072,16 @@ mod biguint_tests { #[test] #[should_fail] fn test_zero_rand_range() { - task_rng().gen_biguint_range(&BigUint::from_uint(54), - &BigUint::from_uint(54)); + task_rng().gen_biguint_range(&FromPrimitive::from_uint(54).unwrap(), + &FromPrimitive::from_uint(54).unwrap()); } #[test] #[should_fail] fn test_negative_rand_range() { let mut rng = task_rng(); - let l = BigUint::from_uint(2352); - let u = BigUint::from_uint(3513); + let l = FromPrimitive::from_uint(2352).unwrap(); + let u = FromPrimitive::from_uint(3513).unwrap(); // Switching u and l should fail: let _n: BigUint = rng.gen_biguint_range(&u, &l); } @@ -1889,16 +2092,17 @@ mod bigint_tests { use super::*; use std::cmp::{Less, Equal, Greater}; - use std::int; - use std::num::{IntConvertible, Zero, One, FromStrRadix}; + use std::i64; + use std::num::{Zero, One, FromStrRadix}; + use std::num::{ToPrimitive, FromPrimitive}; use std::rand::{task_rng}; - use std::uint; + use std::u64; #[test] fn test_from_biguint() { fn check(inp_s: Sign, inp_n: uint, ans_s: Sign, ans_n: uint) { - let inp = BigInt::from_biguint(inp_s, BigUint::from_uint(inp_n)); - let ans = BigInt { sign: ans_s, data: BigUint::from_uint(ans_n)}; + let inp = BigInt::from_biguint(inp_s, FromPrimitive::from_uint(inp_n).unwrap()); + let ans = BigInt { sign: ans_s, data: FromPrimitive::from_uint(ans_n).unwrap()}; assert_eq!(inp, ans); } check(Plus, 1, Plus, 1); @@ -1951,62 +2155,62 @@ mod bigint_tests { } #[test] - fn test_convert_int() { - fn check(b: BigInt, i: int) { - assert!(b == IntConvertible::from_int(i)); - assert!(b.to_int() == i); + fn test_convert_i64() { + fn check(b1: BigInt, i: i64) { + let b2: BigInt = FromPrimitive::from_i64(i).unwrap(); + assert!(b1 == b2); + assert!(b1.to_i64().unwrap() == i); } check(Zero::zero(), 0); check(One::one(), 1); - check(BigInt::from_biguint( - Plus, BigUint::from_uint(int::max_value as uint) - ), int::max_value); + check(i64::min_value.to_bigint().unwrap(), i64::min_value); + check(i64::max_value.to_bigint().unwrap(), i64::max_value); - assert_eq!(BigInt::from_biguint( - Plus, BigUint::from_uint(int::max_value as uint + 1) - ).to_int_opt(), None); - assert_eq!(BigInt::from_biguint( - Plus, BigUint::new(~[1, 2, 3]) - ).to_int_opt(), None); + assert_eq!( + (i64::max_value as u64 + 1).to_bigint().unwrap().to_i64(), + None); - check(BigInt::from_biguint( - Minus, BigUint::new(~[0, 1<<(BigDigit::bits-1)]) - ), int::min_value); - assert_eq!(BigInt::from_biguint( - Minus, BigUint::new(~[1, 1<<(BigDigit::bits-1)]) - ).to_int_opt(), None); - assert_eq!(BigInt::from_biguint( - Minus, BigUint::new(~[1, 2, 3])).to_int_opt(), None); + assert_eq!( + BigInt::from_biguint(Plus, BigUint::new(~[1, 2, 3, 4, 5])).to_i64(), + None); + + assert_eq!( + BigInt::from_biguint(Minus, BigUint::new(~[1, 0, 0, 1<<(BigDigit::bits-1)])).to_i64(), + None); + + assert_eq!( + BigInt::from_biguint(Minus, BigUint::new(~[1, 2, 3, 4, 5])).to_i64(), + None); } #[test] - fn test_convert_uint() { - fn check(b: BigInt, u: uint) { - assert!(b == BigInt::from_uint(u)); - assert!(b.to_uint() == u); + fn test_convert_u64() { + fn check(b1: BigInt, u: u64) { + let b2: BigInt = FromPrimitive::from_u64(u).unwrap(); + assert!(b1 == b2); + assert!(b1.to_u64().unwrap() == u); } check(Zero::zero(), 0); check(One::one(), 1); + check(u64::min_value.to_bigint().unwrap(), u64::min_value); + check(u64::max_value.to_bigint().unwrap(), u64::max_value); - check( - BigInt::from_biguint(Plus, BigUint::from_uint(uint::max_value)), - uint::max_value); - assert_eq!(BigInt::from_biguint( - Plus, BigUint::new(~[1, 2, 3])).to_uint_opt(), None); + assert_eq!( + BigInt::from_biguint(Plus, BigUint::new(~[1, 2, 3, 4, 5])).to_u64(), + None); - assert_eq!(BigInt::from_biguint( - Minus, BigUint::from_uint(uint::max_value)).to_uint_opt(), None); - assert_eq!(BigInt::from_biguint( - Minus, BigUint::new(~[1, 2, 3])).to_uint_opt(), None); + let max_value: BigUint = FromPrimitive::from_u64(u64::max_value).unwrap(); + assert_eq!(BigInt::from_biguint(Minus, max_value).to_u64(), None); + assert_eq!(BigInt::from_biguint(Minus, BigUint::new(~[1, 2, 3, 4, 5])).to_u64(), None); } #[test] fn test_convert_to_biguint() { fn check(n: BigInt, ans_1: BigUint) { - assert_eq!(n.to_biguint(), ans_1); - assert_eq!(n.to_biguint().to_bigint(), n); + assert_eq!(n.to_biguint().unwrap(), ans_1); + assert_eq!(n.to_biguint().unwrap().to_bigint().unwrap(), n); } let zero: BigInt = Zero::zero(); let unsigned_zero: BigUint = Zero::zero(); @@ -2017,7 +2221,7 @@ mod bigint_tests { check(zero, unsigned_zero); check(positive, BigUint::new(~[1,2,3])); - assert_eq!(negative.to_biguint_opt(), None); + assert_eq!(negative.to_biguint(), None); } static sum_triples: &'static [(&'static [BigDigit], @@ -2233,9 +2437,9 @@ mod bigint_tests { #[test] fn test_gcd() { fn check(a: int, b: int, c: int) { - let big_a: BigInt = IntConvertible::from_int(a); - let big_b: BigInt = IntConvertible::from_int(b); - let big_c: BigInt = IntConvertible::from_int(c); + let big_a: BigInt = FromPrimitive::from_int(a).unwrap(); + let big_b: BigInt = FromPrimitive::from_int(b).unwrap(); + let big_c: BigInt = FromPrimitive::from_int(c).unwrap(); assert_eq!(big_a.gcd(&big_b), big_c); } @@ -2253,9 +2457,9 @@ mod bigint_tests { #[test] fn test_lcm() { fn check(a: int, b: int, c: int) { - let big_a: BigInt = IntConvertible::from_int(a); - let big_b: BigInt = IntConvertible::from_int(b); - let big_c: BigInt = IntConvertible::from_int(c); + let big_a: BigInt = FromPrimitive::from_int(a).unwrap(); + let big_b: BigInt = FromPrimitive::from_int(b).unwrap(); + let big_c: BigInt = FromPrimitive::from_int(c).unwrap(); assert_eq!(big_a.lcm(&big_b), big_c); } @@ -2282,13 +2486,14 @@ mod bigint_tests { let zero: BigInt = Zero::zero(); assert_eq!(one.abs_sub(&zero), one); let one: BigInt = One::one(); - assert_eq!(one.abs_sub(&-one), IntConvertible::from_int(2)); + let two: BigInt = FromPrimitive::from_int(2).unwrap(); + assert_eq!(one.abs_sub(&-one), two); } #[test] fn test_to_str_radix() { fn check(n: int, ans: &str) { - let n: BigInt = IntConvertible::from_int(n); + let n: BigInt = FromPrimitive::from_int(n).unwrap(); assert!(ans == n.to_str_radix(10)); } check(10, "10"); @@ -2303,7 +2508,7 @@ mod bigint_tests { fn test_from_str_radix() { fn check(s: &str, ans: Option) { let ans = ans.map_move(|n| { - let x: BigInt = IntConvertible::from_int(n); + let x: BigInt = FromPrimitive::from_int(n).unwrap(); x }); assert_eq!(FromStrRadix::from_str_radix(s, 10), ans); @@ -2339,9 +2544,9 @@ mod bigint_tests { let mut rng = task_rng(); do 10.times { - assert_eq!(rng.gen_bigint_range(&BigInt::from_uint(236), - &BigInt::from_uint(237)), - BigInt::from_uint(236)); + assert_eq!(rng.gen_bigint_range(&FromPrimitive::from_uint(236).unwrap(), + &FromPrimitive::from_uint(237).unwrap()), + FromPrimitive::from_uint(236).unwrap()); } fn check(l: BigInt, u: BigInt) { @@ -2352,8 +2557,8 @@ mod bigint_tests { assert!(n < u); } } - let l = BigInt::from_uint(403469000 + 2352); - let u = BigInt::from_uint(403469000 + 3513); + let l: BigInt = FromPrimitive::from_uint(403469000 + 2352).unwrap(); + let u: BigInt = FromPrimitive::from_uint(403469000 + 3513).unwrap(); check( l.clone(), u.clone()); check(-l.clone(), u.clone()); check(-u.clone(), -l.clone()); @@ -2362,16 +2567,16 @@ mod bigint_tests { #[test] #[should_fail] fn test_zero_rand_range() { - task_rng().gen_bigint_range(&IntConvertible::from_int(54), - &IntConvertible::from_int(54)); + task_rng().gen_bigint_range(&FromPrimitive::from_int(54).unwrap(), + &FromPrimitive::from_int(54).unwrap()); } #[test] #[should_fail] fn test_negative_rand_range() { let mut rng = task_rng(); - let l = BigInt::from_uint(2352); - let u = BigInt::from_uint(3513); + let l = FromPrimitive::from_uint(2352).unwrap(); + let u = FromPrimitive::from_uint(3513).unwrap(); // Switching u and l should fail: let _n: BigInt = rng.gen_bigint_range(&u, &l); } @@ -2381,13 +2586,13 @@ mod bigint_tests { mod bench { use super::*; use std::{iter, util}; - use std::num::{Zero, One}; + use std::num::{FromPrimitive, Zero, One}; use extra::test::BenchHarness; fn factorial(n: uint) -> BigUint { let mut f: BigUint = One::one(); for i in iter::range_inclusive(1, n) { - f = f * BigUint::from_uint(i); + f = f * FromPrimitive::from_uint(i).unwrap(); } f } diff --git a/src/libextra/num/rational.rs b/src/libextra/num/rational.rs index e7142f6f9ff..a8dfdfbfd00 100644 --- a/src/libextra/num/rational.rs +++ b/src/libextra/num/rational.rs @@ -306,7 +306,7 @@ impl mod test { use super::*; - use std::num::{Zero,One,FromStrRadix,IntConvertible}; + use std::num::{Zero,One,FromStrRadix,FromPrimitive}; use std::from_str::FromStr; pub static _0 : Rational = Ratio { numer: 0, denom: 1}; @@ -318,8 +318,8 @@ mod test { pub fn to_big(n: Rational) -> BigRational { Ratio::new( - IntConvertible::from_int(n.numer), - IntConvertible::from_int(n.denom) + FromPrimitive::from_int(n.numer).unwrap(), + FromPrimitive::from_int(n.denom).unwrap() ) } diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs index ded61f975db..52695100b3e 100644 --- a/src/librustc/middle/trans/debuginfo.rs +++ b/src/librustc/middle/trans/debuginfo.rs @@ -107,7 +107,7 @@ use std::hashmap::HashMap; use std::libc::{c_uint, c_ulonglong, c_longlong}; use std::ptr; use std::vec; -use syntax::codemap::Span; +use syntax::codemap::{Span, Pos}; use syntax::{ast, codemap, ast_util, ast_map, opt_vec, visit}; use syntax::parse::token; use syntax::parse::token::special_idents; diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 21517e42169..d5219ed0867 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -26,7 +26,7 @@ use middle::ty; use middle::typeck; use syntax::abi::AbiSet; use syntax::ast_map; -use syntax::codemap::Span; +use syntax::codemap::{Span, Pos}; use syntax::parse::token; use syntax::print::pprust; use syntax::{ast, ast_util}; 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 95b1057dfd0..fde1928f4a3 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 @@ -291,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 @@ -353,6 +349,448 @@ 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`. + #[inline] + fn to_int(&self) -> Option { + self.to_i64().and_then(|x| x.to_int()) + } + + /// Converts the value of `self` to an `i8`. + #[inline] + fn to_i8(&self) -> Option { + self.to_i64().and_then(|x| x.to_i8()) + } + + /// Converts the value of `self` to an `i16`. + #[inline] + fn to_i16(&self) -> Option { + self.to_i64().and_then(|x| x.to_i16()) + } + + /// Converts the value of `self` to an `i32`. + #[inline] + fn to_i32(&self) -> Option { + self.to_i64().and_then(|x| x.to_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_uint(&self) -> Option { + self.to_u64().and_then(|x| x.to_uint()) + } + + /// Converts the value of `self` to an `u8`. + #[inline] + fn to_u8(&self) -> Option { + self.to_u64().and_then(|x| x.to_u8()) + } + + /// Converts the value of `self` to an `u16`. + #[inline] + fn to_u16(&self) -> Option { + self.to_u64().and_then(|x| x.to_u16()) + } + + /// Converts the value of `self` to an `u32`. + #[inline] + fn to_u32(&self) -> Option { + self.to_u64().and_then(|x| x.to_u32()) + } + + /// Converts the value of `self` to an `u64`. + #[inline] + fn to_u64(&self) -> Option { + self.to_u64().and_then(|x| x.to_u64()) + } + + /// Converts the value of `self` to an `f32`. + #[inline] + fn to_f32(&self) -> Option { + self.to_f64().and_then(|x| x.to_f32()) + } + + /// Converts the value of `self` to an `f64`. + #[inline] + fn to_f64(&self) -> Option { + self.to_i64().and_then(|x| x.to_f64()) + } +} + +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 { 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_float!(f32) +impl_to_primitive_float!(f64) + +/// 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. + #[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_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_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_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. + 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. + #[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_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_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_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. + 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_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_i64(n as i64) + } +} + +/// 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, $to_ty:expr) => ( + impl FromPrimitive for $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!(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 /// /// # Example @@ -363,54 +801,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 +869,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 +951,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); @@ -559,51 +967,60 @@ pub fn test_num(ten: T, two: T) { #[cfg(test)] mod tests { use prelude::*; - use uint; use super::*; + use i8; + use i16; + use i32; + use i64; + use int; + use u8; + use u16; + use u32; + use u64; + use uint; macro_rules! test_cast_20( ($_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!(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!(20f32, _20.to_f32().unwrap()); + assert_eq!(20f64, _20.to_f64().unwrap()); - 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, 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)); - 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!(_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()); }) ) @@ -620,6 +1037,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; 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/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 { 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 50a8f184092..70bcb0f7170 100644 --- a/src/libstd/rand/mod.rs +++ b/src/libstd/rand/mod.rs @@ -317,12 +317,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(); } } } diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 5111682f6d0..65a6572fa5e 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -113,6 +113,7 @@ pub trait AstBuilder { expr: @ast::Expr, ident: ast::Ident, args: ~[@ast::Expr]) -> @ast::Expr; fn expr_block(&self, b: ast::Block) -> @ast::Expr; + fn expr_cast(&self, sp: Span, expr: @ast::Expr, ty: ast::Ty) -> @ast::Expr; fn field_imm(&self, span: Span, name: Ident, e: @ast::Expr) -> ast::Field; fn expr_struct(&self, span: Span, path: ast::Path, fields: ~[ast::Field]) -> @ast::Expr; @@ -132,6 +133,10 @@ pub trait AstBuilder { fn expr_str(&self, sp: Span, s: @str) -> @ast::Expr; fn expr_str_uniq(&self, sp: Span, s: @str) -> @ast::Expr; + fn expr_some(&self, sp: Span, expr: @ast::Expr) -> @ast::Expr; + fn expr_none(&self, sp: Span) -> @ast::Expr; + + fn expr_fail(&self, span: Span, msg: @str) -> @ast::Expr; fn expr_unreachable(&self, span: Span) -> @ast::Expr; fn pat(&self, span: Span, pat: ast::Pat_) -> @ast::Pat; @@ -564,7 +569,30 @@ impl AstBuilder for @ExtCtxt { } - fn expr_unreachable(&self, span: Span) -> @ast::Expr { + fn expr_cast(&self, sp: Span, expr: @ast::Expr, ty: ast::Ty) -> @ast::Expr { + self.expr(sp, ast::ExprCast(expr, ty)) + } + + + fn expr_some(&self, sp: Span, expr: @ast::Expr) -> @ast::Expr { + let some = ~[ + self.ident_of("std"), + self.ident_of("option"), + self.ident_of("Some"), + ]; + self.expr_call_global(sp, some, ~[expr]) + } + + fn expr_none(&self, sp: Span) -> @ast::Expr { + let none = self.path_global(sp, ~[ + self.ident_of("std"), + self.ident_of("option"), + self.ident_of("None"), + ]); + self.expr_path(none) + } + + fn expr_fail(&self, span: Span, msg: @str) -> @ast::Expr { let loc = self.codemap().lookup_char_pos(span.lo); self.expr_call_global( span, @@ -575,12 +603,16 @@ impl AstBuilder for @ExtCtxt { self.ident_of("fail_with"), ], ~[ - self.expr_str(span, @"internal error: entered unreachable code"), + self.expr_str(span, msg), self.expr_str(span, loc.file.name), self.expr_uint(span, loc.line), ]) } + fn expr_unreachable(&self, span: Span) -> @ast::Expr { + self.expr_fail(span, @"internal error: entered unreachable code") + } + fn pat(&self, span: Span, pat: ast::Pat_) -> @ast::Pat { @ast::Pat { id: ast::DUMMY_NODE_ID, node: pat, span: span } diff --git a/src/libsyntax/ext/deriving/generic.rs b/src/libsyntax/ext/deriving/generic.rs index f5e45eec7e0..b3fd4f920d8 100644 --- a/src/libsyntax/ext/deriving/generic.rs +++ b/src/libsyntax/ext/deriving/generic.rs @@ -1151,6 +1151,7 @@ pub fn cs_or(enum_nonmatch_f: EnumNonMatchFunc, enum_nonmatch_f, cx, span, substructure) } + /// cs_binop with binop == and #[inline] pub fn cs_and(enum_nonmatch_f: EnumNonMatchFunc, diff --git a/src/libsyntax/ext/deriving/mod.rs b/src/libsyntax/ext/deriving/mod.rs index a428c6704f9..3e65f7bdefb 100644 --- a/src/libsyntax/ext/deriving/mod.rs +++ b/src/libsyntax/ext/deriving/mod.rs @@ -32,6 +32,7 @@ pub mod rand; pub mod to_str; pub mod zero; pub mod default; +pub mod primitive; #[path="cmp/eq.rs"] pub mod eq; @@ -97,9 +98,12 @@ pub fn expand_meta_deriving(cx: @ExtCtxt, "Rand" => expand!(rand::expand_deriving_rand), "ToStr" => expand!(to_str::expand_deriving_to_str), + "Zero" => expand!(zero::expand_deriving_zero), "Default" => expand!(default::expand_deriving_default), + "FromPrimitive" => expand!(primitive::expand_deriving_from_primitive), + ref tname => { cx.span_err(titem.span, format!("unknown \ `deriving` trait: `{}`", *tname)); diff --git a/src/libsyntax/ext/deriving/primitive.rs b/src/libsyntax/ext/deriving/primitive.rs new file mode 100644 index 00000000000..38c30def1d1 --- /dev/null +++ b/src/libsyntax/ext/deriving/primitive.rs @@ -0,0 +1,127 @@ +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use ast::{MetaItem, item, Expr}; +use ast; +use codemap::Span; +use ext::base::ExtCtxt; +use ext::build::AstBuilder; +use ext::deriving::generic::*; + +pub fn expand_deriving_from_primitive(cx: @ExtCtxt, + span: Span, + mitem: @MetaItem, + in_items: ~[@item]) -> ~[@item] { + let trait_def = TraitDef { + path: Path::new(~["std", "num", "FromPrimitive"]), + additional_bounds: ~[], + generics: LifetimeBounds::empty(), + methods: ~[ + MethodDef { + name: "from_i64", + generics: LifetimeBounds::empty(), + explicit_self: None, + args: ~[ + 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("i64", c, s, sub), + }, + MethodDef { + name: "from_u64", + generics: LifetimeBounds::empty(), + explicit_self: None, + args: ~[ + 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("u64", c, s, sub), + }, + ] + }; + + trait_def.expand(cx, span, mitem, in_items) +} + +fn cs_from(name: &str, cx: @ExtCtxt, span: Span, substr: &Substructure) -> @Expr { + let n = match substr.nonself_args { + [n] => n, + _ => cx.span_bug(span, "Incorrect number of arguments in `deriving(FromPrimitive)`") + }; + + match *substr.fields { + StaticStruct(*) => { + cx.span_err(span, "`FromPrimitive` cannot be derived for structs"); + return cx.expr_fail(span, @""); + } + StaticEnum(enum_def, _) => { + if enum_def.variants.is_empty() { + cx.span_err(span, "`FromPrimitive` cannot be derived for enums with no variants"); + return cx.expr_fail(span, @""); + } + + let mut arms = ~[]; + + for variant in enum_def.variants.iter() { + match variant.node.kind { + ast::tuple_variant_kind(ref args) => { + if !args.is_empty() { + cx.span_err(span, "`FromPrimitive` cannot be derived for \ + enum variants with arguments"); + return cx.expr_fail(span, @""); + } + + // expr for `$n == $variant as $name` + let variant = cx.expr_ident(span, variant.node.name); + let ty = cx.ty_ident(span, cx.ident_of(name)); + let cast = cx.expr_cast(span, variant, ty); + let guard = cx.expr_binary(span, ast::BiEq, n, cast); + + // expr for `Some($variant)` + let body = cx.expr_some(span, variant); + + // arm for `_ if $guard => $body` + let arm = ast::Arm { + pats: ~[cx.pat_wild(span)], + guard: Some(guard), + body: cx.block_expr(body), + }; + + arms.push(arm); + } + ast::struct_variant_kind(_) => { + cx.span_err(span, "`FromPrimitive` cannot be derived for enums \ + with struct variants"); + return cx.expr_fail(span, @""); + } + } + } + + // arm for `_ => None` + let arm = ast::Arm { + pats: ~[cx.pat_wild(span)], + guard: None, + body: cx.block_expr(cx.expr_none(span)), + }; + arms.push(arm); + + cx.expr_match(span, n, arms) + } + _ => cx.bug("expected StaticEnum in deriving(FromPrimitive)") + } +} diff --git a/src/test/compile-fail/deriving-primitive.rs b/src/test/compile-fail/deriving-primitive.rs new file mode 100644 index 00000000000..1af0193ca47 --- /dev/null +++ b/src/test/compile-fail/deriving-primitive.rs @@ -0,0 +1,34 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::num::FromPrimitive; +use std::int; + +#[deriving(FromPrimitive)] +struct A { x: int } +//~^^ ERROR `FromPrimitive` cannot be derived for structs +//~^^^ ERROR `FromPrimitive` cannot be derived for structs + +#[deriving(FromPrimitive)] +struct B(int); +//~^^ ERROR `FromPrimitive` cannot be derived for structs +//~^^^ ERROR `FromPrimitive` cannot be derived for structs + +#[deriving(FromPrimitive)] +enum C { Foo(int), Bar(uint) } +//~^^ ERROR `FromPrimitive` cannot be derived for enum variants with arguments +//~^^^ ERROR `FromPrimitive` cannot be derived for enum variants with arguments + +#[deriving(FromPrimitive)] +enum D { Baz { x: int } } +//~^^ ERROR `FromPrimitive` cannot be derived for enums with struct variants +//~^^^ ERROR `FromPrimitive` cannot be derived for enums with struct variants + +pub fn main() {} diff --git a/src/test/run-pass/deriving-primitive.rs b/src/test/run-pass/deriving-primitive.rs new file mode 100644 index 00000000000..f82d77b28ea --- /dev/null +++ b/src/test/run-pass/deriving-primitive.rs @@ -0,0 +1,37 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::num::FromPrimitive; +use std::int; + +#[deriving(Eq, FromPrimitive)] +enum A { + Foo = int::max_value, + Bar = 1, + Baz = 3, + Qux, +} + +pub fn main() { + let x: Option = FromPrimitive::from_int(int::max_value); + assert_eq!(x, Some(Foo)); + + let x: Option = FromPrimitive::from_int(1); + assert_eq!(x, Some(Bar)); + + let x: Option = FromPrimitive::from_int(3); + assert_eq!(x, Some(Baz)); + + let x: Option = FromPrimitive::from_int(4); + assert_eq!(x, Some(Qux)); + + let x: Option = FromPrimitive::from_int(5); + assert_eq!(x, None); +} diff --git a/src/test/run-pass/numeric-method-autoexport.rs b/src/test/run-pass/numeric-method-autoexport.rs index f2df3fc66ea..1422f93e612 100644 --- a/src/test/run-pass/numeric-method-autoexport.rs +++ b/src/test/run-pass/numeric-method-autoexport.rs @@ -36,6 +36,6 @@ pub fn main() { // floats // num - assert_eq!(10f32.to_int(), 10); - assert_eq!(10f64.to_int(), 10); + assert_eq!(10f32.to_int().unwrap(), 10); + assert_eq!(10f64.to_int().unwrap(), 10); } diff --git a/src/test/run-pass/trait-inheritance-num.rs b/src/test/run-pass/trait-inheritance-num.rs index 87de3a2be14..8d3c258558e 100644 --- a/src/test/run-pass/trait-inheritance-num.rs +++ b/src/test/run-pass/trait-inheritance-num.rs @@ -19,7 +19,7 @@ pub trait NumExt: Num + NumCast + Eq + Ord {} pub trait FloatExt: NumExt + ApproxEq {} -fn greater_than_one(n: &T) -> bool { *n > NumCast::from(1) } -fn greater_than_one_float(n: &T) -> bool { *n > NumCast::from(1) } +fn greater_than_one(n: &T) -> bool { *n > NumCast::from(1).unwrap() } +fn greater_than_one_float(n: &T) -> bool { *n > NumCast::from(1).unwrap() } pub fn main() {} diff --git a/src/test/run-pass/trait-inheritance-num0.rs b/src/test/run-pass/trait-inheritance-num0.rs index ae285f3bc95..46efac84907 100644 --- a/src/test/run-pass/trait-inheritance-num0.rs +++ b/src/test/run-pass/trait-inheritance-num0.rs @@ -22,7 +22,7 @@ trait Num { pub trait NumExt: Num + NumCast { } fn greater_than_one(n: &T) -> bool { - n.gt(&NumCast::from(1)) + n.gt(&NumCast::from(1).unwrap()) } pub fn main() {} diff --git a/src/test/run-pass/trait-inheritance-num1.rs b/src/test/run-pass/trait-inheritance-num1.rs index d22a8154a5b..28abae175cd 100644 --- a/src/test/run-pass/trait-inheritance-num1.rs +++ b/src/test/run-pass/trait-inheritance-num1.rs @@ -14,7 +14,7 @@ use std::num::NumCast; pub trait NumExt: Num + NumCast + Ord { } fn greater_than_one(n: &T) -> bool { - *n > NumCast::from(1) + *n > NumCast::from(1).unwrap() } pub fn main() {} diff --git a/src/test/run-pass/trait-inheritance-num3.rs b/src/test/run-pass/trait-inheritance-num3.rs index b7150e873a5..7909f015912 100644 --- a/src/test/run-pass/trait-inheritance-num3.rs +++ b/src/test/run-pass/trait-inheritance-num3.rs @@ -16,7 +16,7 @@ pub trait NumExt: Eq + Ord + Num + NumCast {} impl NumExt for f32 {} fn num_eq_one(n: T) { - println!("{}", n == NumCast::from(1)) + println!("{}", n == NumCast::from(1).unwrap()) } pub fn main() { diff --git a/src/test/run-pass/trait-inheritance-num5.rs b/src/test/run-pass/trait-inheritance-num5.rs index aee954df461..0310dde2a6d 100644 --- a/src/test/run-pass/trait-inheritance-num5.rs +++ b/src/test/run-pass/trait-inheritance-num5.rs @@ -17,7 +17,7 @@ impl NumExt for f32 {} impl NumExt for int {} fn num_eq_one() -> T { - NumCast::from(1) + NumCast::from(1).unwrap() } pub fn main() {