ethnum/uint/
convert.rs

1//! Module contains conversions for [`U256`] to and from primimitive types.
2
3use super::U256;
4use crate::{error::tfie, int::I256};
5use core::{convert::TryFrom, num::TryFromIntError};
6
7macro_rules! impl_from {
8    ($($t:ty),* $(,)?) => {$(
9        impl From<$t> for U256 {
10            #[inline]
11            fn from(value: $t) -> Self {
12                U256::new(value.into())
13            }
14        }
15    )*};
16}
17
18impl_from! {
19    bool, u8, u16, u32, u64, u128,
20}
21
22macro_rules! impl_try_from {
23    ($($t:ty),* $(,)?) => {$(
24        impl TryFrom<$t> for U256 {
25            type Error = TryFromIntError;
26
27            #[inline]
28            fn try_from(value: $t) -> Result<Self, Self::Error> {
29                Ok(U256::new(u128::try_from(value)?))
30            }
31        }
32    )*};
33}
34
35impl_try_from! {
36    i8, i16, i32, i64, i128,
37    isize, usize,
38}
39
40impl TryFrom<I256> for U256 {
41    type Error = TryFromIntError;
42
43    fn try_from(value: I256) -> Result<Self, Self::Error> {
44        if value < 0 {
45            return Err(tfie());
46        }
47        Ok(value.as_u256())
48    }
49}
50
51/// This trait defines `as` conversions (casting) from primitive types to
52/// [`U256`].
53///
54/// [`U256`]: struct.U256.html
55///
56/// # Examples
57///
58/// Note that in Rust casting from a negative signed integer sign to a larger
59/// unsigned interger sign extends. Additionally casting a floating point value
60/// to an integer is a saturating operation, with `NaN` converting to `0`. So:
61///
62/// ```
63/// # use ethnum::{U256, AsU256};
64/// assert_eq!((-1i32).as_u256(), U256::MAX);
65/// assert_eq!(u32::MAX.as_u256(), 0xffffffff);
66///
67/// assert_eq!(f64::NEG_INFINITY.as_u256(), 0);
68/// assert_eq!((-1.0f64).as_u256(), 0);
69/// assert_eq!(f64::INFINITY.as_u256(), U256::MAX);
70/// assert_eq!(2.0f64.powi(257).as_u256(), U256::MAX);
71/// assert_eq!(f64::NAN.as_u256(), 0);
72/// ```
73pub trait AsU256 {
74    /// Perform an `as` conversion to a [`U256`].
75    ///
76    /// [`U256`]: struct.U256.html
77    #[allow(clippy::wrong_self_convention)]
78    fn as_u256(self) -> U256;
79}
80
81impl AsU256 for U256 {
82    #[inline]
83    fn as_u256(self) -> U256 {
84        self
85    }
86}
87
88impl AsU256 for I256 {
89    #[inline]
90    fn as_u256(self) -> U256 {
91        I256::as_u256(self)
92    }
93}
94
95macro_rules! impl_as_u256 {
96    ($($t:ty),* $(,)?) => {$(
97        impl AsU256 for $t {
98            #[inline]
99            fn as_u256(self) -> U256 {
100                #[allow(unused_comparisons)]
101                let hi = if self >= 0 { 0 } else { !0 };
102                U256::from_words(hi, self as _)
103            }
104        }
105    )*};
106}
107
108impl_as_u256! {
109    i8, i16, i32, i64, i128,
110    u8, u16, u32, u64, u128,
111    isize, usize,
112}
113
114impl AsU256 for bool {
115    #[inline]
116    fn as_u256(self) -> U256 {
117        U256::new(self as _)
118    }
119}
120
121macro_rules! impl_as_u256_float {
122    ($($t:ty [$b:ty]),* $(,)?) => {$(
123        impl AsU256 for $t {
124            #[inline]
125            fn as_u256(self) -> U256 {
126                // The conversion follows roughly the same rules as converting
127                // `f64` to other primitive integer types:
128                // - `NaN` => `0`
129                // - `(-∞, 0]` => `0`
130                // - `(0, U256::MAX]` => `value as U256`
131                // - `(U256::MAX, +∞)` => `U256::MAX`
132
133                const M: $b = (<$t>::MANTISSA_DIGITS - 1) as _;
134                const MAN_MASK: $b = !(!0 << M);
135                const MAN_ONE: $b = 1 << M;
136                const EXP_MASK: $b = !0 >> <$t>::MANTISSA_DIGITS;
137                const EXP_OFFSET: $b = EXP_MASK / 2;
138
139                if self >= 1.0 {
140                    let bits = self.to_bits();
141                    let exponent = ((bits >> M) & EXP_MASK) - EXP_OFFSET;
142                    let mantissa = (bits & MAN_MASK) | MAN_ONE;
143                    if exponent <= M {
144                        U256::from(mantissa >> (M - exponent))
145                    } else if exponent < 256 {
146                        U256::from(mantissa) << (exponent - M)
147                    } else {
148                        U256::MAX
149                    }
150                } else {
151                    U256::ZERO
152                }
153            }
154        }
155    )*};
156}
157
158impl_as_u256_float! {
159    f32[u32], f64[u64],
160}
161
162macro_rules! impl_try_into {
163    ($($t:ty),* $(,)?) => {$(
164        impl TryFrom<U256> for $t {
165            type Error = TryFromIntError;
166
167            #[inline]
168            fn try_from(x: U256) -> Result<Self, Self::Error> {
169                if x <= <$t>::MAX.as_u256() {
170                    Ok(*x.low() as _)
171                } else {
172                    Err(tfie())
173                }
174            }
175        }
176    )*};
177}
178
179impl_try_into! {
180    i8, i16, i32, i64, i128,
181    u8, u16, u32, u64, u128,
182    isize, usize,
183}
184
185macro_rules! impl_into_float {
186    ($($t:ty => $f:ident),* $(,)?) => {$(
187        impl From<U256> for $t {
188            #[inline]
189            fn from(x: U256) -> $t {
190                x.$f()
191            }
192        }
193    )*};
194}
195
196impl_into_float! {
197    f32 => as_f32, f64 => as_f64,
198}