use super::U256;
use crate::{error::tfie, int::I256};
use core::{convert::TryFrom, num::TryFromIntError};
macro_rules! impl_from {
($($t:ty),* $(,)?) => {$(
impl From<$t> for U256 {
#[inline]
fn from(value: $t) -> Self {
U256::new(value.into())
}
}
)*};
}
impl_from! {
bool, u8, u16, u32, u64, u128,
}
macro_rules! impl_try_from {
($($t:ty),* $(,)?) => {$(
impl TryFrom<$t> for U256 {
type Error = TryFromIntError;
#[inline]
fn try_from(value: $t) -> Result<Self, Self::Error> {
Ok(U256::new(u128::try_from(value)?))
}
}
)*};
}
impl_try_from! {
i8, i16, i32, i64, i128,
isize, usize,
}
impl TryFrom<I256> for U256 {
type Error = TryFromIntError;
fn try_from(value: I256) -> Result<Self, Self::Error> {
if value < 0 {
return Err(tfie());
}
Ok(value.as_u256())
}
}
pub trait AsU256 {
#[allow(clippy::wrong_self_convention)]
fn as_u256(self) -> U256;
}
impl AsU256 for U256 {
#[inline]
fn as_u256(self) -> U256 {
self
}
}
impl AsU256 for I256 {
#[inline]
fn as_u256(self) -> U256 {
I256::as_u256(self)
}
}
macro_rules! impl_as_u256 {
($($t:ty),* $(,)?) => {$(
impl AsU256 for $t {
#[inline]
fn as_u256(self) -> U256 {
#[allow(unused_comparisons)]
let hi = if self >= 0 { 0 } else { !0 };
U256::from_words(hi, self as _)
}
}
)*};
}
impl_as_u256! {
i8, i16, i32, i64, i128,
u8, u16, u32, u64, u128,
isize, usize,
}
impl AsU256 for bool {
#[inline]
fn as_u256(self) -> U256 {
U256::new(self as _)
}
}
macro_rules! impl_as_u256_float {
($($t:ty [$b:ty]),* $(,)?) => {$(
impl AsU256 for $t {
#[inline]
fn as_u256(self) -> U256 {
const M: $b = (<$t>::MANTISSA_DIGITS - 1) as _;
const MAN_MASK: $b = !(!0 << M);
const MAN_ONE: $b = 1 << M;
const EXP_MASK: $b = !0 >> <$t>::MANTISSA_DIGITS;
const EXP_OFFSET: $b = EXP_MASK / 2;
if self >= 1.0 {
let bits = self.to_bits();
let exponent = ((bits >> M) & EXP_MASK) - EXP_OFFSET;
let mantissa = (bits & MAN_MASK) | MAN_ONE;
if exponent <= M {
U256::from(mantissa >> (M - exponent))
} else if exponent < 256 {
U256::from(mantissa) << (exponent - M)
} else {
U256::MAX
}
} else {
U256::ZERO
}
}
}
)*};
}
impl_as_u256_float! {
f32[u32], f64[u64],
}
macro_rules! impl_try_into {
($($t:ty),* $(,)?) => {$(
impl TryFrom<U256> for $t {
type Error = TryFromIntError;
#[inline]
fn try_from(x: U256) -> Result<Self, Self::Error> {
if x <= <$t>::MAX.as_u256() {
Ok(*x.low() as _)
} else {
Err(tfie())
}
}
}
)*};
}
impl_try_into! {
i8, i16, i32, i64, i128,
u8, u16, u32, u64, u128,
isize, usize,
}
macro_rules! impl_into_float {
($($t:ty => $f:ident),* $(,)?) => {$(
impl From<U256> for $t {
#[inline]
fn from(x: U256) -> $t {
x.$f()
}
}
)*};
}
impl_into_float! {
f32 => as_f32, f64 => as_f64,
}