use std::cmp::PartialEq; use std::fmt::{Debug, Display}; use std::mem::size_of; use std::ops::{Add, Sub, Mul, Div, Rem}; use std::str::FromStr; use ::zero::Zero; use ::one::One; use ::bounded::Bounded; /// A trait that defines what is required to be considered /// a number. pub trait Number: Zero + One + Add + Sub + Mul + Div + Rem + PartialEq + Copy + Clone + Debug + Display { type StrRadixError; /// Create a number from a given string and base radix. /// ///``` /// // Parse the hex value "FF" into an i32. /// // Hex values have a radix (base) of 16. /// use sigils::Number; /// /// let x: i32 = Number::from_str_radix("FF", 16u32).unwrap(); /// # assert_eq!(x, 255i32); ///``` fn from_str_radix(src: &str, radix: u32) -> Result; } /// A trait that defines converting something to a Number. pub trait ToNumber { /// Convert this to an u8. /// None is returned if the conversion is not possible. fn to_u8(&self) -> Option { let option: Option; option = self.to_u64(); match option { Some(val) => { val.to_u8() } None => { None } } } /// Convert this to an u16. /// None is returned if the conversion is not possible. fn to_u16(&self) -> Option { let option: Option; option = self.to_u64(); match option { Some(val) => { val.to_u16() } None => { None } } } /// Convert this to an u32. /// None is returned if the conversion is not possible. fn to_u32(&self) -> Option { let option: Option; option = self.to_u64(); match option { Some(val) => { val.to_u32() } None => { None } } } /// Convert this to an u64. /// None is returned if the conversion is not possible. fn to_u64(&self) -> Option; /// Convert this to an usize. /// None is returned if the conversion is not possible. fn to_usize(&self) -> Option { let option: Option; option = self.to_u64(); match option { Some(val) => { val.to_usize() } None => { None } } } /// Convert this to an i8. /// None is returned if the conversion is not possible. fn to_i8(&self) -> Option { let option: Option; option = self.to_i64(); match option { Some(val) => { val.to_i8() } None => { None } } } /// Convert this to an i16. /// None is returned if the conversion is not possible. fn to_i16(&self) -> Option { let option: Option; option = self.to_i64(); match option { Some(val) => { val.to_i16() } None => { None } } } /// Convert this to an i32. /// None is returned if the conversion is not possible. fn to_i32(&self) -> Option { let option: Option; option = self.to_i64(); match option { Some(val) => { val.to_i32() } None => { None } } } /// Convert this to an i64. /// None is returned if the conversion is not possible. fn to_i64(&self) -> Option; /// Convert this to an isize. /// None is returned if the conversion is not possible. fn to_isize(&self) -> Option { let option: Option; option = self.to_i64(); match option { Some(val) => { val.to_isize() } None => { None } } } /// Convert this to an f32. /// None is returned if the conversion is not possible. fn to_f32(&self) -> Option { let option: Option; option = self.to_f64(); match option { Some(val) => { val.to_f32() } None => { None } } } /// Convert this to an f64. /// None is returned if the conversion is not possible. fn to_f64(&self) -> Option { let option: Option; option = self.to_i64(); match option { Some(val) => { val.to_f64() } None => { None } } } } /// A trait that defines convertung a Number to something else. pub trait FromNumber : Sized { /// Convert an i8 to an optional value of this type. /// None is returned if the conversion is not possible. fn from_i8(number: i8) -> Option { FromNumber::from_i64(number as i64) } /// Convert an i16 to an optional value of this type. /// None is returned if the conversion is not possible. fn from_i16(number: i16) -> Option { FromNumber::from_i64(number as i64) } /// Convert an i32 to an optional value of this type. /// None is returned if the conversion is not possible. fn from_i32(number: i32) -> Option { FromNumber::from_i64(number as i64) } /// Convert an i64 to an optional value of this type. /// None is returned if the conversion is not possible. fn from_i64(number: i64) -> Option; /// Convert an isize to an optional value of this type. /// None is returned if the conversion is not possible. fn from_isize(number: isize) -> Option { FromNumber::from_i64(number as i64) } /// Convert an u8 to an optional value of this type. /// None is returned if the conversion is not possible. fn from_u8(number: u8) -> Option { FromNumber::from_u64(number as u64) } /// Convert an u16 to an optional value of this type. /// None is returned if the conversion is not possible. fn from_u16(number: u16) -> Option { FromNumber::from_u64(number as u64) } /// Convert an u32 to an optional value of this type. /// None is returned if the conversion is not possible. fn from_u32(number: u32) -> Option { FromNumber::from_u64(number as u64) } /// Convert an u64 to an optional value of this type. /// None is returned if the conversion is not possible. fn from_u64(number: u64) -> Option; /// Convert an usize to an optional value of this type. /// None is returned if the conversion is not possible. fn from_usize(number: usize) -> Option { FromNumber::from_u64(number as u64) } /// Convert an f32 to an optional value of this type. /// None is returned if the conversion is not possible. fn from_f32(number: f32) -> Option { FromNumber::from_f64(number as f64) } /// Convert an f64 to an optional value of this type. /// None is returned if the conversion is not possible. fn from_f64(number: f64) -> Option { FromNumber::from_i64(number as i64) } } // Create some macros to ease typing and reading. macro_rules! convert_int_to_int { ($srcType: ty, $dstType: ty, $val: expr) => { { let num: i64; let min_value: $dstType; let max_value: $dstType; num = $val as i64; min_value = Bounded::min_value(); max_value = Bounded::max_value(); if (min_value as i64) <= num && num <= (max_value as i64) { Some($val as $dstType) } else { None } } } } macro_rules! convert_int_to_uint { ($srcType: ty, $dstType: ty, $val: expr) => { { let zero: $srcType; let max_value: $dstType; zero = Zero::zero(); max_value = Bounded::max_value(); if zero <= $val && ($val as u64) <= (max_value as u64) { Some($val as $dstType) } else { None } } } } macro_rules! convert_uint_to_int { ($dstType: ty, $val: expr) => { { let max_value: $dstType; max_value = Bounded::max_value(); if ($val as u64) <= (max_value as u64) { Some($val as $dstType) } else { None } } } } macro_rules! convert_uint_to_uint { ($srcType: ty, $dstType: ty, $val: expr) => { if size_of::<$srcType>() <= size_of::<$dstType>() { Some($val as $dstType) } else { let zero: $srcType; let max_value: $dstType; zero = Zero::zero(); max_value = Bounded::max_value(); if zero <= $val && ($val as u64) <= (max_value as u64) { Some($val as $dstType) } else { None } } } } macro_rules! convert_float_to_float { ($srcType: ty, $dstType: ty, $val: expr) => { if size_of::<$srcType>() <= size_of::<$dstType>() { Some($val as $dstType) } else { let num: f64; let min_value: $srcType; let max_value: $srcType; num = $val as f64; min_value = Bounded::min_value(); max_value = Bounded::max_value(); if (min_value as f64) <= num && num <= (max_value as f64) { Some($val as $dstType) } else { None } } } } macro_rules! int_to_number_impl { ($traitName: ident for $($varType: ty)*) => ($( impl $traitName for $varType { fn to_u8(&self) -> Option { convert_int_to_uint!($varType, u8, *self) } fn to_u16(&self) -> Option { convert_int_to_uint!($varType, u16, *self) } fn to_u32(&self) -> Option { convert_int_to_uint!($varType, u32, *self) } fn to_u64(&self) -> Option { convert_int_to_uint!($varType, u64, *self) } fn to_usize(&self) -> Option { convert_int_to_uint!($varType, usize, *self) } fn to_i8(&self) -> Option { convert_int_to_int!($varType, i8, *self) } fn to_i16(&self) -> Option { convert_int_to_int!($varType, i16, *self) } fn to_i32(&self) -> Option { convert_int_to_int!($varType, i32, *self) } fn to_i64(&self) -> Option { convert_int_to_int!($varType, i64, *self) } fn to_isize(&self) -> Option { convert_int_to_int!($varType, isize, *self) } fn to_f32(&self) -> Option { Some(*self as f32) } fn to_f64(&self) -> Option { Some(*self as f64) } } )*) } macro_rules! uint_to_number_impl { ($traitName: ident for $($varType: ty)*) => ($( impl $traitName for $varType { fn to_u8(&self) -> Option { convert_uint_to_uint!($varType, u8, *self) } fn to_u16(&self) -> Option { convert_uint_to_uint!($varType, u16, *self) } fn to_u32(&self) -> Option { convert_uint_to_uint!($varType, u32, *self) } fn to_u64(&self) -> Option { convert_uint_to_uint!($varType, u64, *self) } fn to_usize(&self) -> Option { convert_uint_to_uint!($varType, usize, *self) } fn to_i8(&self) -> Option { convert_uint_to_int!(i8, *self) } fn to_i16(&self) -> Option { convert_uint_to_int!(i16, *self) } fn to_i32(&self) -> Option { convert_uint_to_int!(i32, *self) } fn to_i64(&self) -> Option { convert_uint_to_int!(i64, *self) } fn to_isize(&self) -> Option { convert_uint_to_int!(isize, *self) } fn to_f32(&self) -> Option { Some(*self as f32) } fn to_f64(&self) -> Option { Some(*self as f64) } } )*) } macro_rules! float_to_number_impl { ($traitName: ident for $($varType: ty)*) => ($( impl $traitName for $varType { fn to_u8(&self) -> Option { Some(*self as u8) } fn to_u16(&self) -> Option { Some(*self as u16) } fn to_u32(&self) -> Option { Some(*self as u32) } fn to_u64(&self) -> Option { Some(*self as u64) } fn to_usize(&self) -> Option { Some(*self as usize) } fn to_i8(&self) -> Option { Some(*self as i8) } fn to_i16(&self) -> Option { Some(*self as i16) } fn to_i32(&self) -> Option { Some(*self as i32) } fn to_i64(&self) -> Option { Some(*self as i64) } fn to_isize(&self) -> Option { Some(*self as isize) } fn to_f32(&self) -> Option { convert_float_to_float!($varType, f32, *self) } fn to_f64(&self) -> Option { convert_float_to_float!($varType, f64, *self) } } )*) } macro_rules! from_number_impl { ($varType: ty, $toTypeFunc: ident) => { impl FromNumber for $varType { fn from_u8(number: u8) -> Option<$varType> { number.$toTypeFunc() } fn from_u16(number: u16) -> Option<$varType> { number.$toTypeFunc() } fn from_u32(number: u32) -> Option<$varType> { number.$toTypeFunc() } fn from_u64(number: u64) -> Option<$varType> { number.$toTypeFunc() } fn from_i8(number: i8) -> Option<$varType> { number.$toTypeFunc() } fn from_i16(number: i16) -> Option<$varType> { number.$toTypeFunc() } fn from_i32(number: i32) -> Option<$varType> { number.$toTypeFunc() } fn from_i64(number: i64) -> Option<$varType> { number.$toTypeFunc() } fn from_f32(number: f32) -> Option<$varType> { number.$toTypeFunc() } fn from_f64(number: f64) -> Option<$varType> { number.$toTypeFunc() } } } } /// A macro to make implementing the Number trait easier for all the /// base integer types in rust. macro_rules! int_number_trait_impl { ($traitName: ident for $($varType: ty)*) => ($( impl $traitName for $varType { type StrRadixError = ::std::num::ParseIntError; fn from_str_radix(src: &str, radix: u32) -> Result { <$varType>::from_str_radix(src, radix) } } )*) } /// A macro to make implementing the Number trait easier for all the /// base float types in rust. macro_rules! float_number_trait_impl { ($traitName: ident for $($varType: ty, $numBytes: expr)*) => ($( impl $traitName for $varType { type StrRadixError = ::std::num::ParseFloatError; fn from_str_radix(src: &str, radix: u32) -> Result { // TODO: Currently this will panic on a non base 10 radix. // This is because the std library deprecated the // from_str_radix function. Until a function can be // written this will use the from_str function and // panic for non base 10 requests. assert!(radix == 10); <$varType>::from_str(src) } } )*) } // Implement the Number trait for the types that are Numbers. int_number_trait_impl!(Number for u8 u16 u32 u64 usize); int_number_trait_impl!(Number for i8 i16 i32 i64 isize); float_number_trait_impl!(Number for f32, 4 f64, 8); // Implement the ToNumber and FromNumber traits for // the types that are Numbers. The FromNumber trait needs // to be defined after ToNumber since FromNumber uses // ToNumber definitions. uint_to_number_impl!(ToNumber for u8 u16 u32 u64 usize); int_to_number_impl!(ToNumber for i8 i16 i32 i64 isize); float_to_number_impl!(ToNumber for f32 f64); from_number_impl!(u8, to_u8); from_number_impl!(u16, to_u16); from_number_impl!(u32, to_u32); from_number_impl!(u64, to_u64); from_number_impl!(usize, to_usize); from_number_impl!(i8, to_i8); from_number_impl!(i16, to_i16); from_number_impl!(i32, to_i32); from_number_impl!(i64, to_i64); from_number_impl!(isize, to_isize); from_number_impl!(f32, to_f32); from_number_impl!(f64, to_f64);