use generic::{read_generic_integer, GenericInteger};
use num::{CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, Integer, One};
use super::GenericFraction;
#[cfg(feature = "with-bigint")]
use super::{BigInt, BigUint};
pub trait TryToConvertFrom<F>: Sized {
fn try_to_convert_from(src: F) -> Option<Self>;
}
macro_rules! convert_impl {
(unsigned; $($T:ty),+) => {
$(
impl<T> TryToConvertFrom<T> for $T
where
T: GenericInteger + Clone + One + CheckedAdd + CheckedDiv + CheckedMul + CheckedSub + PartialOrd,
$T: GenericInteger
{
fn try_to_convert_from(src: T) -> Option<Self> {
read_generic_integer::<Self, T>(src)
.map_or_else(
|| None,
|(sign, val)| if sign.is_positive () { Some(val) } else { None }
)
}
}
)+
};
(signed; $($T:ty),+) => {
$(
impl<T> TryToConvertFrom<T> for $T
where
T: GenericInteger + Clone + One + CheckedAdd + CheckedDiv + CheckedMul + CheckedSub + PartialOrd,
$T: GenericInteger
{
fn try_to_convert_from(src: T) -> Option<Self> {
read_generic_integer::<Self, T>(src)
.map_or_else(
|| None,
|(sign, val)| Some(if sign.is_negative() {-val} else {val})
)
}
}
)+
};
}
convert_impl!(unsigned; u8, u16, u32, u64, u128, usize);
convert_impl!(signed; i8, i16, i32, i64, i128, isize);
#[cfg(feature = "with-bigint")]
convert_impl!(unsigned; BigUint);
#[cfg(feature = "with-bigint")]
convert_impl!(signed; BigInt);
impl<T, F> TryToConvertFrom<GenericFraction<F>> for GenericFraction<T>
where
T: TryToConvertFrom<F> + Clone + Integer,
F: Clone + Integer,
{
fn try_to_convert_from(src: GenericFraction<F>) -> Option<Self> {
match src {
GenericFraction::NaN => Some(GenericFraction::NaN),
GenericFraction::Infinity(sign) => Some(GenericFraction::Infinity(sign)),
GenericFraction::Rational(sign, ratio) => {
let (n, d): (F, F) = ratio.into();
let numer = <T as TryToConvertFrom<F>>::try_to_convert_from(n)?;
let denom = <T as TryToConvertFrom<F>>::try_to_convert_from(d)?;
Some(GenericFraction::Rational(
sign,
super::Ratio::new_raw(numer, denom),
))
}
}
}
}
#[cfg(test)]
mod tests {
use convert::TryToConvertFrom;
use fraction::GenericFraction;
type F1 = GenericFraction<u8>;
type F2 = GenericFraction<i8>;
#[test]
fn try_to_convert_integers() {
{
assert_eq!(Some(127i8), i8::try_to_convert_from(127u8));
assert_eq!(Some(127u8), u8::try_to_convert_from(127i8));
assert_eq!(None, i8::try_to_convert_from(128u8));
assert_eq!(None, u8::try_to_convert_from(-127i8));
assert_eq!(None, u8::try_to_convert_from(256u16));
}
}
#[test]
fn try_to_convert_generic_fraction() {
{
let fu = F1::new(1u8, 2u8);
let fi = F2::try_to_convert_from(fu);
assert!(fi.is_some());
assert_eq!(fi.unwrap(), F2::new(1i8, 2i8));
}
{
let fi = F2::new(1i8, 2i8);
let fu = F1::try_to_convert_from(fi);
assert!(fu.is_some());
assert_eq!(fu.unwrap(), F1::new(1u8, 2u8));
}
{
let fu = F1::infinity();
let fi = F2::try_to_convert_from(fu);
assert!(fi.is_some());
assert_eq!(fi.unwrap(), F2::infinity());
}
{
let fu = F1::neg_infinity();
let fi = F2::try_to_convert_from(fu);
assert!(fi.is_some());
assert_eq!(fi.unwrap(), F2::neg_infinity());
}
}
}