1use super::{utils::twos_complement, BigIntConversionError, ParseSignedError, Sign, Signed};
2use alloc::string::String;
3use core::str::FromStr;
4use ruint::{ToUintError, Uint, UintTryFrom};
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_SRC: usize, const LIMBS_SRC: usize>
53 UintTryFrom<Signed<BITS_SRC, LIMBS_SRC>> for Uint<BITS, LIMBS>
54{
55 #[inline]
56 fn uint_try_from(value: Signed<BITS_SRC, LIMBS_SRC>) -> Result<Self, ToUintError<Self>> {
57 if value.is_negative() {
58 return Err(ToUintError::ValueNegative(BITS, Self::uint_try_from(value.into_raw())?));
59 }
60 Self::uint_try_from(value.into_raw())
61 }
62}
63
64impl<const BITS: usize, const LIMBS: usize, const BITS_SRC: usize, const LIMBS_SRC: usize>
66 UintTryFrom<Uint<BITS_SRC, LIMBS_SRC>> for Signed<BITS, LIMBS>
67{
68 #[inline]
69 fn uint_try_from(value: Uint<BITS_SRC, LIMBS_SRC>) -> Result<Self, ToUintError<Self>> {
70 let resized =
71 Self::from_raw(Uint::<BITS, LIMBS>::uint_try_from(value).map_err(signed_err)?);
72 if resized.is_negative() {
73 return Err(ToUintError::ValueNegative(BITS, resized));
74 }
75 Ok(resized)
76 }
77}
78
79fn signed_err<const BITS: usize, const LIMBS: usize>(
80 err: ToUintError<Uint<BITS, LIMBS>>,
81) -> ToUintError<Signed<BITS, LIMBS>> {
82 match err {
83 ToUintError::ValueTooLarge(b, t) => ToUintError::ValueTooLarge(b, Signed(t)),
84 ToUintError::ValueNegative(b, t) => ToUintError::ValueNegative(b, Signed(t)),
85 ToUintError::NotANumber(b) => ToUintError::NotANumber(b),
86 }
87}
88
89impl<const BITS: usize, const LIMBS: usize> TryFrom<&str> for Signed<BITS, LIMBS> {
90 type Error = ParseSignedError;
91
92 #[inline]
93 fn try_from(value: &str) -> Result<Self, Self::Error> {
94 Self::from_str(value)
95 }
96}
97
98impl<const BITS: usize, const LIMBS: usize> TryFrom<&String> for Signed<BITS, LIMBS> {
99 type Error = ParseSignedError;
100
101 #[inline]
102 fn try_from(value: &String) -> Result<Self, Self::Error> {
103 value.parse()
104 }
105}
106
107impl<const BITS: usize, const LIMBS: usize> TryFrom<String> for Signed<BITS, LIMBS> {
108 type Error = ParseSignedError;
109
110 #[inline]
111 fn try_from(value: String) -> Result<Self, Self::Error> {
112 value.parse()
113 }
114}
115
116impl<const BITS: usize, const LIMBS: usize> FromStr for Signed<BITS, LIMBS> {
117 type Err = ParseSignedError;
118
119 #[inline]
120 fn from_str(s: &str) -> Result<Self, Self::Err> {
121 let (sign, s) = match s.as_bytes().first() {
122 Some(b'+') => (Sign::Positive, &s[1..]),
123 Some(b'-') => (Sign::Negative, &s[1..]),
124 _ => (Sign::Positive, s),
125 };
126 let abs = Uint::<BITS, LIMBS>::from_str(s)?;
127 Self::checked_from_sign_and_abs(sign, abs).ok_or(ParseSignedError::IntegerOverflow)
128 }
129}
130
131impl<const BITS: usize, const LIMBS: usize> TryFrom<Signed<BITS, LIMBS>> for i128 {
132 type Error = BigIntConversionError;
133
134 fn try_from(value: Signed<BITS, LIMBS>) -> Result<Self, Self::Error> {
135 if value.bits() > 128 {
136 return Err(BigIntConversionError);
137 }
138
139 if value.is_positive() {
140 Ok(u128::try_from(value.0).unwrap() as Self)
141 } else {
142 let u = twos_complement(value.0);
143 let u = u128::try_from(u).unwrap() as Self;
144 Ok((!u).wrapping_add(1))
145 }
146 }
147}
148
149impl<const BITS: usize, const LIMBS: usize> TryFrom<i128> for Signed<BITS, LIMBS> {
150 type Error = BigIntConversionError;
151
152 fn try_from(value: i128) -> Result<Self, Self::Error> {
153 let u = value as u128;
154 if value >= 0 {
155 return Self::try_from(u);
156 }
157
158 let tc = (!u).wrapping_add(1);
160 let stc = Uint::<128, 2>::saturating_from(tc);
161 let (num, overflow) = Uint::<BITS, LIMBS>::overflowing_from_limbs_slice(stc.as_limbs());
162 if overflow {
163 return Err(BigIntConversionError);
164 }
165 Ok(Self(twos_complement(num)))
166 }
167}
168
169impl<const BITS: usize, const LIMBS: usize> TryFrom<Signed<BITS, LIMBS>> for u128 {
170 type Error = BigIntConversionError;
171
172 fn try_from(value: Signed<BITS, LIMBS>) -> Result<Self, Self::Error> {
173 if value.is_negative() {
174 return Err(BigIntConversionError);
175 }
176
177 let saturated = Uint::<BITS, LIMBS>::saturating_from(Self::MAX);
178
179 if value > Signed(saturated) {
181 return Err(BigIntConversionError);
182 }
183
184 value.into_raw().try_into().map_err(|_| BigIntConversionError)
185 }
186}
187
188impl<const BITS: usize, const LIMBS: usize> TryFrom<u128> for Signed<BITS, LIMBS> {
189 type Error = BigIntConversionError;
190
191 fn try_from(value: u128) -> Result<Self, Self::Error> {
192 let saturated = Uint::<BITS, LIMBS>::saturating_from(value);
193
194 if value != saturated.to::<u128>() {
195 return Err(BigIntConversionError);
196 }
197
198 Self::try_from(saturated)
199 }
200}
201
202macro_rules! impl_conversions {
204 ($(
205 $u:ty [$actual_low_u:ident -> $low_u:ident, $as_u:ident],
206 $i:ty [$actual_low_i:ident -> $low_i:ident, $as_i:ident];
207 )+) => {
208 impl<const BITS: usize, const LIMBS: usize> Signed<BITS, LIMBS> {
210 $(
211 impl_conversions!(@impl_fns $u, $actual_low_u $low_u $as_u);
212 impl_conversions!(@impl_fns $i, $actual_low_i $low_i $as_i);
213 )+
214 }
215
216 $(
218 impl<const BITS: usize, const LIMBS: usize> TryFrom<$u> for Signed<BITS, LIMBS> {
219 type Error = BigIntConversionError;
220
221 #[inline]
222 fn try_from(value: $u) -> Result<Self, Self::Error> {
223 let u = Uint::<BITS, LIMBS>::try_from(value).map_err(|_| BigIntConversionError)?;
224 Signed::checked_from_sign_and_abs(Sign::Positive, u).ok_or(BigIntConversionError)
225 }
226 }
227
228 impl<const BITS: usize, const LIMBS: usize> TryFrom<$i> for Signed<BITS, LIMBS> {
229 type Error = BigIntConversionError;
230
231 #[inline]
232 fn try_from(value: $i) -> Result<Self, Self::Error> {
233 let uint: $u = value as $u;
234
235 if value.is_positive() {
236 return Self::try_from(uint);
237 }
238
239 let abs = (!uint).wrapping_add(1);
240 let tc = twos_complement(Uint::<BITS, LIMBS>::from(abs));
241 Ok(Self(tc))
242 }
243 }
244
245 impl<const BITS: usize, const LIMBS: usize> TryFrom<Signed<BITS, LIMBS>> for $u {
246 type Error = BigIntConversionError;
247
248 #[inline]
249 fn try_from(value: Signed<BITS, LIMBS>) -> Result<$u, Self::Error> {
250 u128::try_from(value)?.try_into().map_err(|_| BigIntConversionError)
251 }
252 }
253
254 impl<const BITS: usize, const LIMBS: usize> TryFrom<Signed<BITS, LIMBS>> for $i {
255 type Error = BigIntConversionError;
256
257 #[inline]
258 fn try_from(value: Signed<BITS, LIMBS>) -> Result<$i, Self::Error> {
259 i128::try_from(value)?.try_into().map_err(|_| BigIntConversionError)
260 }
261 }
262 )+
263 };
264
265 (@impl_fns $t:ty, $actual_low:ident $low:ident $as:ident) => {
266 #[inline]
268 pub const fn $low(&self) -> $t {
269 if BITS == 0 {
270 return 0
271 }
272
273 self.0.as_limbs()[0] as $t
274 }
275
276 #[doc = concat!("Conversion to ", stringify!($t) ," with overflow checking.")]
277 #[doc = concat!("Panics if the number is outside the ", stringify!($t), " valid range.")]
281 #[inline]
282 #[track_caller]
283 pub fn $as(&self) -> $t {
284 <$t as TryFrom<Self>>::try_from(*self).unwrap()
285 }
286 };
287}
288
289impl_conversions! {
290 u8 [low_u64 -> low_u8, as_u8], i8 [low_u64 -> low_i8, as_i8];
291 u16 [low_u64 -> low_u16, as_u16], i16 [low_u64 -> low_i16, as_i16];
292 u32 [low_u64 -> low_u32, as_u32], i32 [low_u64 -> low_i32, as_i32];
293 u64 [low_u64 -> low_u64, as_u64], i64 [low_u64 -> low_i64, as_i64];
294 usize[low_u64 -> low_usize, as_usize], isize[low_u64 -> low_isize, as_isize];
295}