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 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 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
144macro_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 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 $(
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 #[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 #[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}