num_bigint/bigint/
convert.rs

1use super::Sign::{self, Minus, NoSign, Plus};
2use super::{BigInt, ToBigInt};
3
4use crate::TryFromBigIntError;
5use crate::{BigUint, ParseBigIntError, ToBigUint};
6
7use alloc::vec::Vec;
8use core::cmp::Ordering::{Equal, Greater, Less};
9use core::convert::TryFrom;
10use core::str::{self, FromStr};
11use num_traits::{FromPrimitive, Num, One, ToPrimitive, Zero};
12
13impl FromStr for BigInt {
14    type Err = ParseBigIntError;
15
16    #[inline]
17    fn from_str(s: &str) -> Result<BigInt, ParseBigIntError> {
18        BigInt::from_str_radix(s, 10)
19    }
20}
21
22impl Num for BigInt {
23    type FromStrRadixErr = ParseBigIntError;
24
25    /// Creates and initializes a [`BigInt`].
26    #[inline]
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
41impl ToPrimitive for BigInt {
42    #[inline]
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]
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]
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]
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]
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]
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
107macro_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
129impl_try_from_bigint!(u8, ToPrimitive::to_u8);
130impl_try_from_bigint!(u16, ToPrimitive::to_u16);
131impl_try_from_bigint!(u32, ToPrimitive::to_u32);
132impl_try_from_bigint!(u64, ToPrimitive::to_u64);
133impl_try_from_bigint!(usize, ToPrimitive::to_usize);
134impl_try_from_bigint!(u128, ToPrimitive::to_u128);
135
136impl_try_from_bigint!(i8, ToPrimitive::to_i8);
137impl_try_from_bigint!(i16, ToPrimitive::to_i16);
138impl_try_from_bigint!(i32, ToPrimitive::to_i32);
139impl_try_from_bigint!(i64, ToPrimitive::to_i64);
140impl_try_from_bigint!(isize, ToPrimitive::to_isize);
141impl_try_from_bigint!(i128, ToPrimitive::to_i128);
142
143impl FromPrimitive for BigInt {
144    #[inline]
145    fn from_i64(n: i64) -> Option<BigInt> {
146        Some(BigInt::from(n))
147    }
148
149    #[inline]
150    fn from_i128(n: i128) -> Option<BigInt> {
151        Some(BigInt::from(n))
152    }
153
154    #[inline]
155    fn from_u64(n: u64) -> Option<BigInt> {
156        Some(BigInt::from(n))
157    }
158
159    #[inline]
160    fn from_u128(n: u128) -> Option<BigInt> {
161        Some(BigInt::from(n))
162    }
163
164    #[inline]
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
175impl From<i64> for BigInt {
176    #[inline]
177    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
190impl From<i128> for BigInt {
191    #[inline]
192    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
205macro_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
216impl_bigint_from_int!(i8);
217impl_bigint_from_int!(i16);
218impl_bigint_from_int!(i32);
219impl_bigint_from_int!(isize);
220
221impl From<u64> for BigInt {
222    #[inline]
223    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
235impl From<u128> for BigInt {
236    #[inline]
237    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
249macro_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
260impl_bigint_from_uint!(u8);
261impl_bigint_from_uint!(u16);
262impl_bigint_from_uint!(u32);
263impl_bigint_from_uint!(usize);
264
265impl From<BigUint> for BigInt {
266    #[inline]
267    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
279impl ToBigInt for BigInt {
280    #[inline]
281    fn to_bigint(&self) -> Option<BigInt> {
282        Some(self.clone())
283    }
284}
285
286impl ToBigInt for BigUint {
287    #[inline]
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
300impl ToBigUint for BigInt {
301    #[inline]
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
311impl TryFrom<&BigInt> for BigUint {
312    type Error = TryFromBigIntError<()>;
313
314    #[inline]
315    fn try_from(value: &BigInt) -> Result<BigUint, TryFromBigIntError<()>> {
316        value
317            .to_biguint()
318            .ok_or_else(|| TryFromBigIntError::new(()))
319    }
320}
321
322impl TryFrom<BigInt> for BigUint {
323    type Error = TryFromBigIntError<BigInt>;
324
325    #[inline]
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
335macro_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
346impl_to_bigint!(isize, FromPrimitive::from_isize);
347impl_to_bigint!(i8, FromPrimitive::from_i8);
348impl_to_bigint!(i16, FromPrimitive::from_i16);
349impl_to_bigint!(i32, FromPrimitive::from_i32);
350impl_to_bigint!(i64, FromPrimitive::from_i64);
351impl_to_bigint!(i128, FromPrimitive::from_i128);
352
353impl_to_bigint!(usize, FromPrimitive::from_usize);
354impl_to_bigint!(u8, FromPrimitive::from_u8);
355impl_to_bigint!(u16, FromPrimitive::from_u16);
356impl_to_bigint!(u32, FromPrimitive::from_u32);
357impl_to_bigint!(u64, FromPrimitive::from_u64);
358impl_to_bigint!(u128, FromPrimitive::from_u128);
359
360impl_to_bigint!(f32, FromPrimitive::from_f32);
361impl_to_bigint!(f64, FromPrimitive::from_f64);
362
363impl From<bool> for BigInt {
364    fn from(x: bool) -> Self {
365        if x {
366            One::one()
367        } else {
368            Self::ZERO
369        }
370    }
371}
372
373#[inline]
374pub(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]
392pub(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]
410pub(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]
426pub(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]
446fn 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]
453fn 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]
460fn twos_complement<'a, I>(digits: I)
461where
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}