alloy_primitives/signed/
conversions.rs

1use super::{utils::twos_complement, BigIntConversionError, ParseSignedError, Sign, Signed};
2use alloc::string::String;
3use core::str::FromStr;
4use ruint::Uint;
5
6impl<const BITS: usize, const LIMBS: usize> TryFrom<Uint<BITS, LIMBS>> for Signed<BITS, LIMBS> {
7    type Error = BigIntConversionError;
8
9    #[inline]
10    fn try_from(from: Uint<BITS, LIMBS>) -> Result<Self, Self::Error> {
11        let value = Self(from);
12        match value.sign() {
13            Sign::Positive => Ok(value),
14            Sign::Negative => Err(BigIntConversionError),
15        }
16    }
17}
18
19impl<const BITS: usize, const LIMBS: usize> TryFrom<Signed<BITS, LIMBS>> for Uint<BITS, LIMBS> {
20    type Error = BigIntConversionError;
21
22    #[inline]
23    fn try_from(value: Signed<BITS, LIMBS>) -> Result<Self, Self::Error> {
24        match value.sign() {
25            Sign::Positive => Ok(value.0),
26            Sign::Negative => Err(BigIntConversionError),
27        }
28    }
29}
30
31impl<const BITS: usize, const LIMBS: usize> TryFrom<&str> for Signed<BITS, LIMBS> {
32    type Error = ParseSignedError;
33
34    #[inline]
35    fn try_from(value: &str) -> Result<Self, Self::Error> {
36        Self::from_str(value)
37    }
38}
39
40impl<const BITS: usize, const LIMBS: usize> TryFrom<&String> for Signed<BITS, LIMBS> {
41    type Error = ParseSignedError;
42
43    #[inline]
44    fn try_from(value: &String) -> Result<Self, Self::Error> {
45        value.parse()
46    }
47}
48
49impl<const BITS: usize, const LIMBS: usize> TryFrom<String> for Signed<BITS, LIMBS> {
50    type Error = ParseSignedError;
51
52    #[inline]
53    fn try_from(value: String) -> Result<Self, Self::Error> {
54        value.parse()
55    }
56}
57
58impl<const BITS: usize, const LIMBS: usize> FromStr for Signed<BITS, LIMBS> {
59    type Err = ParseSignedError;
60
61    #[inline]
62    fn from_str(s: &str) -> Result<Self, Self::Err> {
63        let (sign, s) = match s.as_bytes().first() {
64            Some(b'+') => (Sign::Positive, &s[1..]),
65            Some(b'-') => (Sign::Negative, &s[1..]),
66            _ => (Sign::Positive, s),
67        };
68        let abs = Uint::<BITS, LIMBS>::from_str(s)?;
69        Self::checked_from_sign_and_abs(sign, abs).ok_or(ParseSignedError::IntegerOverflow)
70    }
71}
72
73impl<const BITS: usize, const LIMBS: usize> TryFrom<Signed<BITS, LIMBS>> for i128 {
74    type Error = BigIntConversionError;
75
76    fn try_from(value: Signed<BITS, LIMBS>) -> Result<Self, Self::Error> {
77        if value.bits() > 128 {
78            return Err(BigIntConversionError);
79        }
80
81        if value.is_positive() {
82            Ok(u128::try_from(value.0).unwrap() as Self)
83        } else {
84            let u = twos_complement(value.0);
85            let u = u128::try_from(u).unwrap() as Self;
86            Ok((!u).wrapping_add(1))
87        }
88    }
89}
90
91impl<const BITS: usize, const LIMBS: usize> TryFrom<i128> for Signed<BITS, LIMBS> {
92    type Error = BigIntConversionError;
93
94    fn try_from(value: i128) -> Result<Self, Self::Error> {
95        let u = value as u128;
96        if value >= 0 {
97            return Self::try_from(u);
98        }
99
100        // This is a bit messy :(
101        let tc = (!u).wrapping_add(1);
102        let stc = Uint::<128, 2>::saturating_from(tc);
103        let (num, overflow) = Uint::<BITS, LIMBS>::overflowing_from_limbs_slice(stc.as_limbs());
104        if overflow {
105            return Err(BigIntConversionError);
106        }
107        Ok(Self(twos_complement(num)))
108    }
109}
110
111impl<const BITS: usize, const LIMBS: usize> TryFrom<Signed<BITS, LIMBS>> for u128 {
112    type Error = BigIntConversionError;
113
114    fn try_from(value: Signed<BITS, LIMBS>) -> Result<Self, Self::Error> {
115        if value.is_negative() {
116            return Err(BigIntConversionError);
117        }
118
119        let saturated = Uint::<BITS, LIMBS>::saturating_from(Self::MAX);
120
121        // if the value is greater than the saturated value, return an error
122        if value > Signed(saturated) {
123            return Err(BigIntConversionError);
124        }
125
126        value.into_raw().try_into().map_err(|_| BigIntConversionError)
127    }
128}
129
130impl<const BITS: usize, const LIMBS: usize> TryFrom<u128> for Signed<BITS, LIMBS> {
131    type Error = BigIntConversionError;
132
133    fn try_from(value: u128) -> Result<Self, Self::Error> {
134        let saturated = Uint::<BITS, LIMBS>::saturating_from(value);
135
136        if value != saturated.to::<u128>() {
137            return Err(BigIntConversionError);
138        }
139
140        Self::try_from(saturated)
141    }
142}
143
144// conversions
145macro_rules! impl_conversions {
146    ($(
147        $u:ty [$actual_low_u:ident -> $low_u:ident, $as_u:ident],
148        $i:ty [$actual_low_i:ident -> $low_i:ident, $as_i:ident];
149    )+) => {
150        // low_*, as_*
151        impl<const BITS: usize, const LIMBS: usize> Signed<BITS, LIMBS> {
152            $(
153                impl_conversions!(@impl_fns $u, $actual_low_u $low_u $as_u);
154                impl_conversions!(@impl_fns $i, $actual_low_i $low_i $as_i);
155            )+
156        }
157
158        // From<$>, TryFrom
159        $(
160            impl<const BITS: usize, const LIMBS: usize> TryFrom<$u> for Signed<BITS, LIMBS> {
161                type Error = BigIntConversionError;
162
163                #[inline]
164                fn try_from(value: $u) -> Result<Self, Self::Error> {
165                    let u = Uint::<BITS, LIMBS>::try_from(value).map_err(|_| BigIntConversionError)?;
166                    Signed::checked_from_sign_and_abs(Sign::Positive, u).ok_or(BigIntConversionError)
167                }
168            }
169
170            impl<const BITS: usize, const LIMBS: usize> TryFrom<$i> for Signed<BITS, LIMBS> {
171                type Error = BigIntConversionError;
172
173                #[inline]
174                fn try_from(value: $i) -> Result<Self, Self::Error> {
175                    let uint: $u = value as $u;
176
177                    if value.is_positive() {
178                        return Self::try_from(uint);
179                    }
180
181                    let abs = (!uint).wrapping_add(1);
182                    let tc = twos_complement(Uint::<BITS, LIMBS>::from(abs));
183                    Ok(Self(tc))
184                }
185            }
186
187            impl<const BITS: usize, const LIMBS: usize> TryFrom<Signed<BITS, LIMBS>> for $u {
188                type Error = BigIntConversionError;
189
190                #[inline]
191                fn try_from(value: Signed<BITS, LIMBS>) -> Result<$u, Self::Error> {
192                    u128::try_from(value)?.try_into().map_err(|_| BigIntConversionError)
193                }
194            }
195
196            impl<const BITS: usize, const LIMBS: usize> TryFrom<Signed<BITS, LIMBS>> for $i {
197                type Error = BigIntConversionError;
198
199                #[inline]
200                fn try_from(value: Signed<BITS, LIMBS>) -> Result<$i, Self::Error> {
201                    i128::try_from(value)?.try_into().map_err(|_| BigIntConversionError)
202                }
203            }
204        )+
205    };
206
207    (@impl_fns $t:ty, $actual_low:ident $low:ident $as:ident) => {
208        /// Low word.
209        #[inline]
210        pub const fn $low(&self) -> $t {
211            if BITS == 0 {
212                return 0
213            }
214
215            self.0.as_limbs()[0] as $t
216        }
217
218        #[doc = concat!("Conversion to ", stringify!($t) ," with overflow checking.")]
219        ///
220        /// # Panics
221        ///
222        #[doc = concat!("Panics if the number is outside the ", stringify!($t), " valid range.")]
223        #[inline]
224        #[track_caller]
225        pub fn $as(&self) -> $t {
226            <$t as TryFrom<Self>>::try_from(*self).unwrap()
227        }
228    };
229}
230
231impl_conversions! {
232    u8   [low_u64  -> low_u8,    as_u8],    i8   [low_u64  -> low_i8,    as_i8];
233    u16  [low_u64  -> low_u16,   as_u16],   i16  [low_u64  -> low_i16,   as_i16];
234    u32  [low_u64  -> low_u32,   as_u32],   i32  [low_u64  -> low_i32,   as_i32];
235    u64  [low_u64  -> low_u64,   as_u64],   i64  [low_u64  -> low_i64,   as_i64];
236    usize[low_u64  -> low_usize, as_usize], isize[low_u64  -> low_isize, as_isize];
237}