use std::convert::TryFrom;
use traiter::numbers::{FractExp, LoadExp, One, Zero};
use crate::traits::UncheckedToInt;
use super::try_from_string::TryFromString;
use super::types::{BigInt, Sign, TryFromFloatError, TryFromStringError};
macro_rules! try_from_float_impl {
($($float:ty)*) => ($(
impl<
Digit: Copy + Zero,
const DIGIT_BITNESS: usize,
> TryFrom<$float> for BigInt<Digit, DIGIT_BITNESS>
where
Self: Zero,
$float: From<Digit> + UncheckedToInt<Digit>,
{
type Error = TryFromFloatError;
fn try_from(mut value: $float) -> Result<Self, Self::Error> {
debug_assert!(
usize::BITS < i32::BITS || DIGIT_BITNESS < (i32::MAX as usize)
);
if value.is_infinite() {
Err(TryFromFloatError::Infinity)
} else if value.is_nan() {
Err(TryFromFloatError::NaN)
} else if value.abs() < (1 as $float) {
Ok(Self::zero())
} else {
let mut sign = Sign::one();
if value.is_sign_negative() {
sign = -sign;
value = -value;
}
let (fraction, exponent) = value.fract_exp();
let mut digits = vec![
Digit::zero();
((exponent as usize) - 1) / DIGIT_BITNESS + 1
];
let mut fraction =
fraction.load_exp((exponent - 1) % (DIGIT_BITNESS as i32) + 1);
for index in (0..digits.len()).rev() {
let digit =
unsafe { <$float>::unchecked_to_int(fraction) };
digits[index] = digit;
fraction -= <$float>::from(digit);
fraction = fraction.load_exp(DIGIT_BITNESS as i32);
}
Ok(Self { sign, digits })
}
}
}
)*)
}
try_from_float_impl!(f32 f64);
impl<Digit, const DIGIT_BITNESS: usize> TryFrom<&str>
for BigInt<Digit, DIGIT_BITNESS>
where
Self: TryFromString,
{
type Error = TryFromStringError;
fn try_from(string: &str) -> Result<Self, Self::Error> {
Self::try_from_string(string, 0)
}
}