sigils/src/number.rs

818 lines
17 KiB
Rust
Raw Normal View History

use std::cmp::PartialEq;
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<Output=Self> + Sub<Output=Self> +
Mul<Output=Self> + Div<Output=Self> + Rem<Output=Self> +
PartialEq + Copy + Clone
{
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<Self, Self::StrRadixError>;
}
/// 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<u8>
{
let option: Option<u64>;
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<u16>
{
let option: Option<u64>;
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<u32>
{
let option: Option<u64>;
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<u64>;
/// Convert this to an usize.
/// None is returned if the conversion is not possible.
fn to_usize(&self) -> Option<usize>
{
let option: Option<u64>;
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<i8>
{
let option: Option<i64>;
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<i16>
{
let option: Option<i64>;
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<i32>
{
let option: Option<i64>;
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<i64>;
/// Convert this to an isize.
/// None is returned if the conversion is not possible.
fn to_isize(&self) -> Option<isize>
{
let option: Option<i64>;
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<f32>
{
let option: Option<f64>;
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<f64>
{
let option: Option<i64>;
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<Self>
{
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<Self>
{
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<Self>
{
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<Self>;
/// 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<Self>
{
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<Self>
{
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<Self>
{
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<Self>
{
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<Self>;
/// 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<Self>
{
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<Self>
{
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<Self>
{
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<u8>
{
convert_int_to_uint!($varType, u8, *self)
}
fn to_u16(&self) -> Option<u16>
{
convert_int_to_uint!($varType, u16, *self)
}
fn to_u32(&self) -> Option<u32>
{
convert_int_to_uint!($varType, u32, *self)
}
fn to_u64(&self) -> Option<u64>
{
convert_int_to_uint!($varType, u64, *self)
}
fn to_usize(&self) -> Option<usize>
{
convert_int_to_uint!($varType, usize, *self)
}
fn to_i8(&self) -> Option<i8>
{
convert_int_to_int!($varType, i8, *self)
}
fn to_i16(&self) -> Option<i16>
{
convert_int_to_int!($varType, i16, *self)
}
fn to_i32(&self) -> Option<i32>
{
convert_int_to_int!($varType, i32, *self)
}
fn to_i64(&self) -> Option<i64>
{
convert_int_to_int!($varType, i64, *self)
}
fn to_isize(&self) -> Option<isize>
{
convert_int_to_int!($varType, isize, *self)
}
fn to_f32(&self) -> Option<f32>
{
Some(*self as f32)
}
fn to_f64(&self) -> Option<f64>
{
Some(*self as f64)
}
}
)*)
}
macro_rules! uint_to_number_impl
{
($traitName: ident for $($varType: ty)*) =>
($(
impl $traitName for $varType
{
fn to_u8(&self) -> Option<u8>
{
convert_uint_to_uint!($varType, u8, *self)
}
fn to_u16(&self) -> Option<u16>
{
convert_uint_to_uint!($varType, u16, *self)
}
fn to_u32(&self) -> Option<u32>
{
convert_uint_to_uint!($varType, u32, *self)
}
fn to_u64(&self) -> Option<u64>
{
convert_uint_to_uint!($varType, u64, *self)
}
fn to_usize(&self) -> Option<usize>
{
convert_uint_to_uint!($varType, usize, *self)
}
fn to_i8(&self) -> Option<i8>
{
convert_uint_to_int!(i8, *self)
}
fn to_i16(&self) -> Option<i16>
{
convert_uint_to_int!(i16, *self)
}
fn to_i32(&self) -> Option<i32>
{
convert_uint_to_int!(i32, *self)
}
fn to_i64(&self) -> Option<i64>
{
convert_uint_to_int!(i64, *self)
}
fn to_isize(&self) -> Option<isize>
{
convert_uint_to_int!(isize, *self)
}
fn to_f32(&self) -> Option<f32>
{
Some(*self as f32)
}
fn to_f64(&self) -> Option<f64>
{
Some(*self as f64)
}
}
)*)
}
macro_rules! float_to_number_impl
{
($traitName: ident for $($varType: ty)*) =>
($(
impl $traitName for $varType
{
fn to_u8(&self) -> Option<u8>
{
Some(*self as u8)
}
fn to_u16(&self) -> Option<u16>
{
Some(*self as u16)
}
fn to_u32(&self) -> Option<u32>
{
Some(*self as u32)
}
fn to_u64(&self) -> Option<u64>
{
Some(*self as u64)
}
fn to_usize(&self) -> Option<usize>
{
Some(*self as usize)
}
fn to_i8(&self) -> Option<i8>
{
Some(*self as i8)
}
fn to_i16(&self) -> Option<i16>
{
Some(*self as i16)
}
fn to_i32(&self) -> Option<i32>
{
Some(*self as i32)
}
fn to_i64(&self) -> Option<i64>
{
Some(*self as i64)
}
fn to_isize(&self) -> Option<isize>
{
Some(*self as isize)
}
fn to_f32(&self) -> Option<f32>
{
convert_float_to_float!($varType, f32, *self)
}
fn to_f64(&self) -> Option<f64>
{
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<Self, ::std::num::ParseIntError>
{
<$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<Self, ::std::num::ParseFloatError>
{
// 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);