1use super::Sign::{self, Minus, NoSign, Plus};
2use super::{BigInt, ToBigInt};
3
4use crate::std_alloc::Vec;
5#[cfg(has_try_from)]
6use crate::TryFromBigIntError;
7use crate::{BigUint, ParseBigIntError, ToBigUint};
8
9use core::cmp::Ordering::{Equal, Greater, Less};
10#[cfg(has_try_from)]
11use core::convert::TryFrom;
12use core::str::{self, FromStr};
13use num_traits::{FromPrimitive, Num, ToPrimitive, Zero};
14
15impl FromStr for BigInt {
16 type Err = ParseBigIntError;
17
18 #[inline]
19 fn from_str(s: &str) -> Result<BigInt, ParseBigIntError> {
20 BigInt::from_str_radix(s, 10)
21 }
22}
23
24impl Num for BigInt {
25 type FromStrRadixErr = ParseBigIntError;
26
27 #[inline]
29 fn from_str_radix(mut s: &str, radix: u32) -> Result<BigInt, ParseBigIntError> {
30 let sign = if s.starts_with('-') {
31 let tail = &s[1..];
32 if !tail.starts_with('+') {
33 s = tail
34 }
35 Minus
36 } else {
37 Plus
38 };
39 let bu = BigUint::from_str_radix(s, radix)?;
40 Ok(BigInt::from_biguint(sign, bu))
41 }
42}
43
44impl ToPrimitive for BigInt {
45 #[inline]
46 fn to_i64(&self) -> Option<i64> {
47 match self.sign {
48 Plus => self.data.to_i64(),
49 NoSign => Some(0),
50 Minus => {
51 let n = self.data.to_u64()?;
52 let m: u64 = 1 << 63;
53 match n.cmp(&m) {
54 Less => Some(-(n as i64)),
55 Equal => Some(core::i64::MIN),
56 Greater => None,
57 }
58 }
59 }
60 }
61
62 #[inline]
63 fn to_i128(&self) -> Option<i128> {
64 match self.sign {
65 Plus => self.data.to_i128(),
66 NoSign => Some(0),
67 Minus => {
68 let n = self.data.to_u128()?;
69 let m: u128 = 1 << 127;
70 match n.cmp(&m) {
71 Less => Some(-(n as i128)),
72 Equal => Some(core::i128::MIN),
73 Greater => None,
74 }
75 }
76 }
77 }
78
79 #[inline]
80 fn to_u64(&self) -> Option<u64> {
81 match self.sign {
82 Plus => self.data.to_u64(),
83 NoSign => Some(0),
84 Minus => None,
85 }
86 }
87
88 #[inline]
89 fn to_u128(&self) -> Option<u128> {
90 match self.sign {
91 Plus => self.data.to_u128(),
92 NoSign => Some(0),
93 Minus => None,
94 }
95 }
96
97 #[inline]
98 fn to_f32(&self) -> Option<f32> {
99 let n = self.data.to_f32()?;
100 Some(if self.sign == Minus { -n } else { n })
101 }
102
103 #[inline]
104 fn to_f64(&self) -> Option<f64> {
105 let n = self.data.to_f64()?;
106 Some(if self.sign == Minus { -n } else { n })
107 }
108}
109
110macro_rules! impl_try_from_bigint {
111 ($T:ty, $to_ty:path) => {
112 #[cfg(has_try_from)]
113 impl TryFrom<&BigInt> for $T {
114 type Error = TryFromBigIntError<()>;
115
116 #[inline]
117 fn try_from(value: &BigInt) -> Result<$T, TryFromBigIntError<()>> {
118 $to_ty(value).ok_or(TryFromBigIntError::new(()))
119 }
120 }
121
122 #[cfg(has_try_from)]
123 impl TryFrom<BigInt> for $T {
124 type Error = TryFromBigIntError<BigInt>;
125
126 #[inline]
127 fn try_from(value: BigInt) -> Result<$T, TryFromBigIntError<BigInt>> {
128 <$T>::try_from(&value).map_err(|_| TryFromBigIntError::new(value))
129 }
130 }
131 };
132}
133
134impl_try_from_bigint!(u8, ToPrimitive::to_u8);
135impl_try_from_bigint!(u16, ToPrimitive::to_u16);
136impl_try_from_bigint!(u32, ToPrimitive::to_u32);
137impl_try_from_bigint!(u64, ToPrimitive::to_u64);
138impl_try_from_bigint!(usize, ToPrimitive::to_usize);
139impl_try_from_bigint!(u128, ToPrimitive::to_u128);
140
141impl_try_from_bigint!(i8, ToPrimitive::to_i8);
142impl_try_from_bigint!(i16, ToPrimitive::to_i16);
143impl_try_from_bigint!(i32, ToPrimitive::to_i32);
144impl_try_from_bigint!(i64, ToPrimitive::to_i64);
145impl_try_from_bigint!(isize, ToPrimitive::to_isize);
146impl_try_from_bigint!(i128, ToPrimitive::to_i128);
147
148impl FromPrimitive for BigInt {
149 #[inline]
150 fn from_i64(n: i64) -> Option<BigInt> {
151 Some(BigInt::from(n))
152 }
153
154 #[inline]
155 fn from_i128(n: i128) -> Option<BigInt> {
156 Some(BigInt::from(n))
157 }
158
159 #[inline]
160 fn from_u64(n: u64) -> Option<BigInt> {
161 Some(BigInt::from(n))
162 }
163
164 #[inline]
165 fn from_u128(n: u128) -> Option<BigInt> {
166 Some(BigInt::from(n))
167 }
168
169 #[inline]
170 fn from_f64(n: f64) -> Option<BigInt> {
171 if n >= 0.0 {
172 BigUint::from_f64(n).map(BigInt::from)
173 } else {
174 let x = BigUint::from_f64(-n)?;
175 Some(-BigInt::from(x))
176 }
177 }
178}
179
180impl From<i64> for BigInt {
181 #[inline]
182 fn from(n: i64) -> Self {
183 if n >= 0 {
184 BigInt::from(n as u64)
185 } else {
186 let u = core::u64::MAX - (n as u64) + 1;
187 BigInt {
188 sign: Minus,
189 data: BigUint::from(u),
190 }
191 }
192 }
193}
194
195impl From<i128> for BigInt {
196 #[inline]
197 fn from(n: i128) -> Self {
198 if n >= 0 {
199 BigInt::from(n as u128)
200 } else {
201 let u = core::u128::MAX - (n as u128) + 1;
202 BigInt {
203 sign: Minus,
204 data: BigUint::from(u),
205 }
206 }
207 }
208}
209
210macro_rules! impl_bigint_from_int {
211 ($T:ty) => {
212 impl From<$T> for BigInt {
213 #[inline]
214 fn from(n: $T) -> Self {
215 BigInt::from(n as i64)
216 }
217 }
218 };
219}
220
221impl_bigint_from_int!(i8);
222impl_bigint_from_int!(i16);
223impl_bigint_from_int!(i32);
224impl_bigint_from_int!(isize);
225
226impl From<u64> for BigInt {
227 #[inline]
228 fn from(n: u64) -> Self {
229 if n > 0 {
230 BigInt {
231 sign: Plus,
232 data: BigUint::from(n),
233 }
234 } else {
235 BigInt::zero()
236 }
237 }
238}
239
240impl From<u128> for BigInt {
241 #[inline]
242 fn from(n: u128) -> Self {
243 if n > 0 {
244 BigInt {
245 sign: Plus,
246 data: BigUint::from(n),
247 }
248 } else {
249 BigInt::zero()
250 }
251 }
252}
253
254macro_rules! impl_bigint_from_uint {
255 ($T:ty) => {
256 impl From<$T> for BigInt {
257 #[inline]
258 fn from(n: $T) -> Self {
259 BigInt::from(n as u64)
260 }
261 }
262 };
263}
264
265impl_bigint_from_uint!(u8);
266impl_bigint_from_uint!(u16);
267impl_bigint_from_uint!(u32);
268impl_bigint_from_uint!(usize);
269
270impl From<BigUint> for BigInt {
271 #[inline]
272 fn from(n: BigUint) -> Self {
273 if n.is_zero() {
274 BigInt::zero()
275 } else {
276 BigInt {
277 sign: Plus,
278 data: n,
279 }
280 }
281 }
282}
283
284impl ToBigInt for BigInt {
285 #[inline]
286 fn to_bigint(&self) -> Option<BigInt> {
287 Some(self.clone())
288 }
289}
290
291impl ToBigInt for BigUint {
292 #[inline]
293 fn to_bigint(&self) -> Option<BigInt> {
294 if self.is_zero() {
295 Some(Zero::zero())
296 } else {
297 Some(BigInt {
298 sign: Plus,
299 data: self.clone(),
300 })
301 }
302 }
303}
304
305impl ToBigUint for BigInt {
306 #[inline]
307 fn to_biguint(&self) -> Option<BigUint> {
308 match self.sign() {
309 Plus => Some(self.data.clone()),
310 NoSign => Some(Zero::zero()),
311 Minus => None,
312 }
313 }
314}
315
316#[cfg(has_try_from)]
317impl TryFrom<&BigInt> for BigUint {
318 type Error = TryFromBigIntError<()>;
319
320 #[inline]
321 fn try_from(value: &BigInt) -> Result<BigUint, TryFromBigIntError<()>> {
322 value
323 .to_biguint()
324 .ok_or_else(|| TryFromBigIntError::new(()))
325 }
326}
327
328#[cfg(has_try_from)]
329impl TryFrom<BigInt> for BigUint {
330 type Error = TryFromBigIntError<BigInt>;
331
332 #[inline]
333 fn try_from(value: BigInt) -> Result<BigUint, TryFromBigIntError<BigInt>> {
334 if value.sign() == Sign::Minus {
335 Err(TryFromBigIntError::new(value))
336 } else {
337 Ok(value.data)
338 }
339 }
340}
341
342macro_rules! impl_to_bigint {
343 ($T:ty, $from_ty:path) => {
344 impl ToBigInt for $T {
345 #[inline]
346 fn to_bigint(&self) -> Option<BigInt> {
347 $from_ty(*self)
348 }
349 }
350 };
351}
352
353impl_to_bigint!(isize, FromPrimitive::from_isize);
354impl_to_bigint!(i8, FromPrimitive::from_i8);
355impl_to_bigint!(i16, FromPrimitive::from_i16);
356impl_to_bigint!(i32, FromPrimitive::from_i32);
357impl_to_bigint!(i64, FromPrimitive::from_i64);
358impl_to_bigint!(i128, FromPrimitive::from_i128);
359
360impl_to_bigint!(usize, FromPrimitive::from_usize);
361impl_to_bigint!(u8, FromPrimitive::from_u8);
362impl_to_bigint!(u16, FromPrimitive::from_u16);
363impl_to_bigint!(u32, FromPrimitive::from_u32);
364impl_to_bigint!(u64, FromPrimitive::from_u64);
365impl_to_bigint!(u128, FromPrimitive::from_u128);
366
367impl_to_bigint!(f32, FromPrimitive::from_f32);
368impl_to_bigint!(f64, FromPrimitive::from_f64);
369
370#[inline]
371pub(super) fn from_signed_bytes_be(digits: &[u8]) -> BigInt {
372 let sign = match digits.first() {
373 Some(v) if *v > 0x7f => Sign::Minus,
374 Some(_) => Sign::Plus,
375 None => return BigInt::zero(),
376 };
377
378 if sign == Sign::Minus {
379 let mut digits = Vec::from(digits);
381 twos_complement_be(&mut digits);
382 BigInt::from_biguint(sign, BigUint::from_bytes_be(&*digits))
383 } else {
384 BigInt::from_biguint(sign, BigUint::from_bytes_be(digits))
385 }
386}
387
388#[inline]
389pub(super) fn from_signed_bytes_le(digits: &[u8]) -> BigInt {
390 let sign = match digits.last() {
391 Some(v) if *v > 0x7f => Sign::Minus,
392 Some(_) => Sign::Plus,
393 None => return BigInt::zero(),
394 };
395
396 if sign == Sign::Minus {
397 let mut digits = Vec::from(digits);
399 twos_complement_le(&mut digits);
400 BigInt::from_biguint(sign, BigUint::from_bytes_le(&*digits))
401 } else {
402 BigInt::from_biguint(sign, BigUint::from_bytes_le(digits))
403 }
404}
405
406#[inline]
407pub(super) fn to_signed_bytes_be(x: &BigInt) -> Vec<u8> {
408 let mut bytes = x.data.to_bytes_be();
409 let first_byte = bytes.first().cloned().unwrap_or(0);
410 if first_byte > 0x7f
411 && !(first_byte == 0x80 && bytes.iter().skip(1).all(Zero::is_zero) && x.sign == Sign::Minus)
412 {
413 bytes.insert(0, 0);
415 }
416 if x.sign == Sign::Minus {
417 twos_complement_be(&mut bytes);
418 }
419 bytes
420}
421
422#[inline]
423pub(super) fn to_signed_bytes_le(x: &BigInt) -> Vec<u8> {
424 let mut bytes = x.data.to_bytes_le();
425 let last_byte = bytes.last().cloned().unwrap_or(0);
426 if last_byte > 0x7f
427 && !(last_byte == 0x80
428 && bytes.iter().rev().skip(1).all(Zero::is_zero)
429 && x.sign == Sign::Minus)
430 {
431 bytes.push(0);
433 }
434 if x.sign == Sign::Minus {
435 twos_complement_le(&mut bytes);
436 }
437 bytes
438}
439
440#[inline]
443fn twos_complement_le(digits: &mut [u8]) {
444 twos_complement(digits)
445}
446
447#[inline]
450fn twos_complement_be(digits: &mut [u8]) {
451 twos_complement(digits.iter_mut().rev())
452}
453
454#[inline]
457fn twos_complement<'a, I>(digits: I)
458where
459 I: IntoIterator<Item = &'a mut u8>,
460{
461 let mut carry = true;
462 for d in digits {
463 *d = !*d;
464 if carry {
465 *d = d.wrapping_add(1);
466 carry = d.is_zero();
467 }
468 }
469}