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