1use super::{BigIntConversionError, ParseSignedError, Sign, Signed, utils::twos_complement};
2use alloc::string::String;
3use core::str::FromStr;
4use ruint::{FromUintError, ToUintError, Uint, UintTryFrom, UintTryTo};
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, const BITS_SRC: usize, const LIMBS_SRC: usize>
33 UintTryFrom<Signed<BITS_SRC, LIMBS_SRC>> for Signed<BITS, LIMBS>
34{
35 #[inline]
36 fn uint_try_from(value: Signed<BITS_SRC, LIMBS_SRC>) -> Result<Self, ToUintError<Self>> {
37 let (sign, abs) = value.into_sign_and_abs();
38 let resized = Self::from_raw(Uint::<BITS, LIMBS>::uint_try_from(abs).map_err(signed_err)?);
39 if resized.is_negative() {
40 return Err(ToUintError::ValueNegative(BITS, resized));
41 }
42 Ok(match sign {
43 Sign::Negative => {
44 resized.checked_neg().ok_or(ToUintError::ValueTooLarge(BITS, resized))?
45 }
46 Sign::Positive => resized,
47 })
48 }
49}
50
51impl<const BITS: usize, const LIMBS: usize, const BITS_TARGET: usize, const LIMBS_TARGET: usize>
53 UintTryTo<Signed<BITS_TARGET, LIMBS_TARGET>> for Signed<BITS, LIMBS>
54{
55 #[inline]
56 fn uint_try_to(
57 &self,
58 ) -> Result<Signed<BITS_TARGET, LIMBS_TARGET>, FromUintError<Signed<BITS_TARGET, LIMBS_TARGET>>>
59 {
60 let (sign, abs) = self.into_sign_and_abs();
61 let resized = Signed::<BITS_TARGET, LIMBS_TARGET>::from_raw(
62 Uint::uint_try_to(&abs).map_err(|e| match e {
63 FromUintError::Overflow(b, t, v) => {
64 FromUintError::Overflow(b, Signed(t), Signed(v))
65 }
66 })?,
67 );
68 if resized.is_negative() {
69 return Err(FromUintError::Overflow(BITS_TARGET, resized, Signed::MAX));
70 }
71 Ok(match sign {
72 Sign::Negative => resized.checked_neg().ok_or(FromUintError::Overflow(
73 BITS_TARGET,
74 resized,
75 Signed::MAX,
76 ))?,
77 Sign::Positive => resized,
78 })
79 }
80}
81
82impl<const BITS: usize, const LIMBS: usize, const BITS_SRC: usize, const LIMBS_SRC: usize>
84 UintTryFrom<Signed<BITS_SRC, LIMBS_SRC>> for Uint<BITS, LIMBS>
85{
86 #[inline]
87 fn uint_try_from(value: Signed<BITS_SRC, LIMBS_SRC>) -> Result<Self, ToUintError<Self>> {
88 if value.is_negative() {
89 return Err(ToUintError::ValueNegative(BITS, Self::uint_try_from(value.into_raw())?));
90 }
91 Self::uint_try_from(value.into_raw())
92 }
93}
94
95impl<const BITS: usize, const LIMBS: usize, const BITS_TARGET: usize, const LIMBS_TARGET: usize>
97 UintTryTo<Uint<BITS_TARGET, LIMBS_TARGET>> for Signed<BITS, LIMBS>
98{
99 #[inline]
100 fn uint_try_to(
101 &self,
102 ) -> Result<Uint<BITS_TARGET, LIMBS_TARGET>, FromUintError<Uint<BITS_TARGET, LIMBS_TARGET>>>
103 {
104 if self.is_negative() {
105 return Err(FromUintError::Overflow(BITS_TARGET, Uint::ZERO, Uint::MAX));
106 }
107 Uint::uint_try_to(&self.into_raw())
108 }
109}
110
111impl<const BITS: usize, const LIMBS: usize, const BITS_SRC: usize, const LIMBS_SRC: usize>
113 UintTryFrom<Uint<BITS_SRC, LIMBS_SRC>> for Signed<BITS, LIMBS>
114{
115 #[inline]
116 fn uint_try_from(value: Uint<BITS_SRC, LIMBS_SRC>) -> Result<Self, ToUintError<Self>> {
117 let resized =
118 Self::from_raw(Uint::<BITS, LIMBS>::uint_try_from(value).map_err(signed_err)?);
119 if resized.is_negative() {
120 return Err(ToUintError::ValueNegative(BITS, resized));
121 }
122 Ok(resized)
123 }
124}
125
126impl<const BITS: usize, const LIMBS: usize, const BITS_TARGET: usize, const LIMBS_TARGET: usize>
128 UintTryTo<Signed<BITS_TARGET, LIMBS_TARGET>> for Uint<BITS, LIMBS>
129{
130 #[inline]
131 fn uint_try_to(
132 &self,
133 ) -> Result<Signed<BITS_TARGET, LIMBS_TARGET>, FromUintError<Signed<BITS_TARGET, LIMBS_TARGET>>>
134 {
135 let resized = Signed::<BITS_TARGET, LIMBS_TARGET>::from_raw(
136 Self::uint_try_to(self).map_err(|e| match e {
137 FromUintError::Overflow(b, t, v) => {
138 FromUintError::Overflow(b, Signed(t), Signed(v))
139 }
140 })?,
141 );
142 if resized.is_negative() {
143 return Err(FromUintError::Overflow(BITS_TARGET, resized, Signed::MAX));
144 }
145 Ok(resized)
146 }
147}
148
149fn signed_err<const BITS: usize, const LIMBS: usize>(
150 err: ToUintError<Uint<BITS, LIMBS>>,
151) -> ToUintError<Signed<BITS, LIMBS>> {
152 match err {
153 ToUintError::ValueTooLarge(b, t) => ToUintError::ValueTooLarge(b, Signed(t)),
154 ToUintError::ValueNegative(b, t) => ToUintError::ValueNegative(b, Signed(t)),
155 ToUintError::NotANumber(b) => ToUintError::NotANumber(b),
156 }
157}
158
159impl<const BITS: usize, const LIMBS: usize> TryFrom<&str> for Signed<BITS, LIMBS> {
160 type Error = ParseSignedError;
161
162 #[inline]
163 fn try_from(value: &str) -> Result<Self, Self::Error> {
164 Self::from_str(value)
165 }
166}
167
168impl<const BITS: usize, const LIMBS: usize> TryFrom<&String> for Signed<BITS, LIMBS> {
169 type Error = ParseSignedError;
170
171 #[inline]
172 fn try_from(value: &String) -> Result<Self, Self::Error> {
173 value.parse()
174 }
175}
176
177impl<const BITS: usize, const LIMBS: usize> TryFrom<String> for Signed<BITS, LIMBS> {
178 type Error = ParseSignedError;
179
180 #[inline]
181 fn try_from(value: String) -> Result<Self, Self::Error> {
182 value.parse()
183 }
184}
185
186impl<const BITS: usize, const LIMBS: usize> FromStr for Signed<BITS, LIMBS> {
187 type Err = ParseSignedError;
188
189 #[inline]
190 fn from_str(s: &str) -> Result<Self, Self::Err> {
191 let (sign, s) = match s.as_bytes().first() {
192 Some(b'+') => (Sign::Positive, &s[1..]),
193 Some(b'-') => (Sign::Negative, &s[1..]),
194 _ => (Sign::Positive, s),
195 };
196 let abs = Uint::<BITS, LIMBS>::from_str(s)?;
197 Self::checked_from_sign_and_abs(sign, abs).ok_or(ParseSignedError::IntegerOverflow)
198 }
199}
200
201impl<const BITS: usize, const LIMBS: usize> TryFrom<Signed<BITS, LIMBS>> for i128 {
202 type Error = BigIntConversionError;
203
204 fn try_from(value: Signed<BITS, LIMBS>) -> Result<Self, Self::Error> {
205 if value.bits() > 128 {
206 return Err(BigIntConversionError);
207 }
208
209 if value.is_positive() {
210 Ok(u128::try_from(value.0).unwrap() as Self)
211 } else {
212 let u = twos_complement(value.0);
213 let u = u128::try_from(u).unwrap() as Self;
214 Ok((!u).wrapping_add(1))
215 }
216 }
217}
218
219impl<const BITS: usize, const LIMBS: usize> TryFrom<i128> for Signed<BITS, LIMBS> {
220 type Error = BigIntConversionError;
221
222 fn try_from(value: i128) -> Result<Self, Self::Error> {
223 let u = value as u128;
224 if value >= 0 {
225 return Self::try_from(u);
226 }
227
228 let tc = (!u).wrapping_add(1);
230 let stc = Uint::<128, 2>::saturating_from(tc);
231 let (num, overflow) = Uint::<BITS, LIMBS>::overflowing_from_limbs_slice(stc.as_limbs());
232 if overflow {
233 return Err(BigIntConversionError);
234 }
235 Ok(Self(twos_complement(num)))
236 }
237}
238
239impl<const BITS: usize, const LIMBS: usize> TryFrom<Signed<BITS, LIMBS>> for u128 {
240 type Error = BigIntConversionError;
241
242 fn try_from(value: Signed<BITS, LIMBS>) -> Result<Self, Self::Error> {
243 if value.is_negative() {
244 return Err(BigIntConversionError);
245 }
246
247 let saturated = Uint::<BITS, LIMBS>::saturating_from(Self::MAX);
248
249 if value > Signed(saturated) {
251 return Err(BigIntConversionError);
252 }
253
254 value.into_raw().try_into().map_err(|_| BigIntConversionError)
255 }
256}
257
258impl<const BITS: usize, const LIMBS: usize> TryFrom<u128> for Signed<BITS, LIMBS> {
259 type Error = BigIntConversionError;
260
261 fn try_from(value: u128) -> Result<Self, Self::Error> {
262 let saturated = Uint::<BITS, LIMBS>::saturating_from(value);
263
264 if value != saturated.to::<u128>() {
265 return Err(BigIntConversionError);
266 }
267
268 Self::try_from(saturated)
269 }
270}
271
272macro_rules! impl_conversions {
274 ($(
275 $u:ty [$actual_low_u:ident -> $low_u:ident, $as_u:ident],
276 $i:ty [$actual_low_i:ident -> $low_i:ident, $as_i:ident];
277 )+) => {
278 impl<const BITS: usize, const LIMBS: usize> Signed<BITS, LIMBS> {
280 $(
281 impl_conversions!(@impl_fns $u, $actual_low_u $low_u $as_u);
282 impl_conversions!(@impl_fns $i, $actual_low_i $low_i $as_i);
283 )+
284 }
285
286 $(
288 impl<const BITS: usize, const LIMBS: usize> TryFrom<$u> for Signed<BITS, LIMBS> {
289 type Error = BigIntConversionError;
290
291 #[inline]
292 fn try_from(value: $u) -> Result<Self, Self::Error> {
293 let u = Uint::<BITS, LIMBS>::try_from(value).map_err(|_| BigIntConversionError)?;
294 Signed::checked_from_sign_and_abs(Sign::Positive, u).ok_or(BigIntConversionError)
295 }
296 }
297
298 impl<const BITS: usize, const LIMBS: usize> TryFrom<$i> for Signed<BITS, LIMBS> {
299 type Error = BigIntConversionError;
300
301 #[inline]
302 fn try_from(value: $i) -> Result<Self, Self::Error> {
303 let uint: $u = value as $u;
304
305 if value.is_positive() {
306 return Self::try_from(uint);
307 }
308
309 let abs = (!uint).wrapping_add(1);
310 let tc = twos_complement(Uint::<BITS, LIMBS>::from(abs));
311 Ok(Self(tc))
312 }
313 }
314
315 impl<const BITS: usize, const LIMBS: usize> TryFrom<Signed<BITS, LIMBS>> for $u {
316 type Error = BigIntConversionError;
317
318 #[inline]
319 fn try_from(value: Signed<BITS, LIMBS>) -> Result<$u, Self::Error> {
320 u128::try_from(value)?.try_into().map_err(|_| BigIntConversionError)
321 }
322 }
323
324 impl<const BITS: usize, const LIMBS: usize> TryFrom<Signed<BITS, LIMBS>> for $i {
325 type Error = BigIntConversionError;
326
327 #[inline]
328 fn try_from(value: Signed<BITS, LIMBS>) -> Result<$i, Self::Error> {
329 i128::try_from(value)?.try_into().map_err(|_| BigIntConversionError)
330 }
331 }
332 )+
333 };
334
335 (@impl_fns $t:ty, $actual_low:ident $low:ident $as:ident) => {
336 #[inline]
338 pub const fn $low(&self) -> $t {
339 if BITS == 0 {
340 return 0
341 }
342
343 self.0.as_limbs()[0] as $t
344 }
345
346 #[doc = concat!("Conversion to ", stringify!($t) ," with overflow checking.")]
347 #[doc = concat!("Panics if the number is outside the ", stringify!($t), " valid range.")]
351 #[inline]
352 #[track_caller]
353 pub fn $as(&self) -> $t {
354 <$t as TryFrom<Self>>::try_from(*self).unwrap()
355 }
356 };
357}
358
359impl_conversions! {
360 u8 [low_u64 -> low_u8, as_u8], i8 [low_u64 -> low_i8, as_i8];
361 u16 [low_u64 -> low_u16, as_u16], i16 [low_u64 -> low_i16, as_i16];
362 u32 [low_u64 -> low_u32, as_u32], i32 [low_u64 -> low_i32, as_i32];
363 u64 [low_u64 -> low_u64, as_u64], i64 [low_u64 -> low_i64, as_i64];
364 usize[low_u64 -> low_usize, as_usize], isize[low_u64 -> low_isize, as_isize];
365}