summaryrefslogtreecommitdiffstats
path: root/rust/vendor/num-bigint/src/bigint/convert.rs
diff options
context:
space:
mode:
Diffstat (limited to 'rust/vendor/num-bigint/src/bigint/convert.rs')
-rw-r--r--rust/vendor/num-bigint/src/bigint/convert.rs479
1 files changed, 479 insertions, 0 deletions
diff --git a/rust/vendor/num-bigint/src/bigint/convert.rs b/rust/vendor/num-bigint/src/bigint/convert.rs
new file mode 100644
index 0000000..c4f888b
--- /dev/null
+++ b/rust/vendor/num-bigint/src/bigint/convert.rs
@@ -0,0 +1,479 @@
+use super::Sign::{self, Minus, NoSign, Plus};
+use super::{BigInt, ToBigInt};
+
+use crate::std_alloc::Vec;
+#[cfg(has_try_from)]
+use crate::TryFromBigIntError;
+use crate::{BigUint, ParseBigIntError, ToBigUint};
+
+use core::cmp::Ordering::{Equal, Greater, Less};
+#[cfg(has_try_from)]
+use core::convert::TryFrom;
+use core::str::{self, FromStr};
+use num_traits::{FromPrimitive, Num, One, ToPrimitive, Zero};
+
+impl FromStr for BigInt {
+ type Err = ParseBigIntError;
+
+ #[inline]
+ fn from_str(s: &str) -> Result<BigInt, ParseBigIntError> {
+ BigInt::from_str_radix(s, 10)
+ }
+}
+
+impl Num for BigInt {
+ type FromStrRadixErr = ParseBigIntError;
+
+ /// Creates and initializes a [`BigInt`].
+ #[inline]
+ fn from_str_radix(mut s: &str, radix: u32) -> Result<BigInt, ParseBigIntError> {
+ let sign = if s.starts_with('-') {
+ let tail = &s[1..];
+ if !tail.starts_with('+') {
+ s = tail
+ }
+ Minus
+ } else {
+ Plus
+ };
+ let bu = BigUint::from_str_radix(s, radix)?;
+ Ok(BigInt::from_biguint(sign, bu))
+ }
+}
+
+impl ToPrimitive for BigInt {
+ #[inline]
+ fn to_i64(&self) -> Option<i64> {
+ match self.sign {
+ Plus => self.data.to_i64(),
+ NoSign => Some(0),
+ Minus => {
+ let n = self.data.to_u64()?;
+ let m: u64 = 1 << 63;
+ match n.cmp(&m) {
+ Less => Some(-(n as i64)),
+ Equal => Some(core::i64::MIN),
+ Greater => None,
+ }
+ }
+ }
+ }
+
+ #[inline]
+ fn to_i128(&self) -> Option<i128> {
+ match self.sign {
+ Plus => self.data.to_i128(),
+ NoSign => Some(0),
+ Minus => {
+ let n = self.data.to_u128()?;
+ let m: u128 = 1 << 127;
+ match n.cmp(&m) {
+ Less => Some(-(n as i128)),
+ Equal => Some(core::i128::MIN),
+ Greater => None,
+ }
+ }
+ }
+ }
+
+ #[inline]
+ fn to_u64(&self) -> Option<u64> {
+ match self.sign {
+ Plus => self.data.to_u64(),
+ NoSign => Some(0),
+ Minus => None,
+ }
+ }
+
+ #[inline]
+ fn to_u128(&self) -> Option<u128> {
+ match self.sign {
+ Plus => self.data.to_u128(),
+ NoSign => Some(0),
+ Minus => None,
+ }
+ }
+
+ #[inline]
+ fn to_f32(&self) -> Option<f32> {
+ let n = self.data.to_f32()?;
+ Some(if self.sign == Minus { -n } else { n })
+ }
+
+ #[inline]
+ fn to_f64(&self) -> Option<f64> {
+ let n = self.data.to_f64()?;
+ Some(if self.sign == Minus { -n } else { n })
+ }
+}
+
+macro_rules! impl_try_from_bigint {
+ ($T:ty, $to_ty:path) => {
+ #[cfg(has_try_from)]
+ impl TryFrom<&BigInt> for $T {
+ type Error = TryFromBigIntError<()>;
+
+ #[inline]
+ fn try_from(value: &BigInt) -> Result<$T, TryFromBigIntError<()>> {
+ $to_ty(value).ok_or(TryFromBigIntError::new(()))
+ }
+ }
+
+ #[cfg(has_try_from)]
+ impl TryFrom<BigInt> for $T {
+ type Error = TryFromBigIntError<BigInt>;
+
+ #[inline]
+ fn try_from(value: BigInt) -> Result<$T, TryFromBigIntError<BigInt>> {
+ <$T>::try_from(&value).map_err(|_| TryFromBigIntError::new(value))
+ }
+ }
+ };
+}
+
+impl_try_from_bigint!(u8, ToPrimitive::to_u8);
+impl_try_from_bigint!(u16, ToPrimitive::to_u16);
+impl_try_from_bigint!(u32, ToPrimitive::to_u32);
+impl_try_from_bigint!(u64, ToPrimitive::to_u64);
+impl_try_from_bigint!(usize, ToPrimitive::to_usize);
+impl_try_from_bigint!(u128, ToPrimitive::to_u128);
+
+impl_try_from_bigint!(i8, ToPrimitive::to_i8);
+impl_try_from_bigint!(i16, ToPrimitive::to_i16);
+impl_try_from_bigint!(i32, ToPrimitive::to_i32);
+impl_try_from_bigint!(i64, ToPrimitive::to_i64);
+impl_try_from_bigint!(isize, ToPrimitive::to_isize);
+impl_try_from_bigint!(i128, ToPrimitive::to_i128);
+
+impl FromPrimitive for BigInt {
+ #[inline]
+ fn from_i64(n: i64) -> Option<BigInt> {
+ Some(BigInt::from(n))
+ }
+
+ #[inline]
+ fn from_i128(n: i128) -> Option<BigInt> {
+ Some(BigInt::from(n))
+ }
+
+ #[inline]
+ fn from_u64(n: u64) -> Option<BigInt> {
+ Some(BigInt::from(n))
+ }
+
+ #[inline]
+ fn from_u128(n: u128) -> Option<BigInt> {
+ Some(BigInt::from(n))
+ }
+
+ #[inline]
+ fn from_f64(n: f64) -> Option<BigInt> {
+ if n >= 0.0 {
+ BigUint::from_f64(n).map(BigInt::from)
+ } else {
+ let x = BigUint::from_f64(-n)?;
+ Some(-BigInt::from(x))
+ }
+ }
+}
+
+impl From<i64> for BigInt {
+ #[inline]
+ fn from(n: i64) -> Self {
+ if n >= 0 {
+ BigInt::from(n as u64)
+ } else {
+ let u = core::u64::MAX - (n as u64) + 1;
+ BigInt {
+ sign: Minus,
+ data: BigUint::from(u),
+ }
+ }
+ }
+}
+
+impl From<i128> for BigInt {
+ #[inline]
+ fn from(n: i128) -> Self {
+ if n >= 0 {
+ BigInt::from(n as u128)
+ } else {
+ let u = core::u128::MAX - (n as u128) + 1;
+ BigInt {
+ sign: Minus,
+ data: BigUint::from(u),
+ }
+ }
+ }
+}
+
+macro_rules! impl_bigint_from_int {
+ ($T:ty) => {
+ impl From<$T> for BigInt {
+ #[inline]
+ fn from(n: $T) -> Self {
+ BigInt::from(n as i64)
+ }
+ }
+ };
+}
+
+impl_bigint_from_int!(i8);
+impl_bigint_from_int!(i16);
+impl_bigint_from_int!(i32);
+impl_bigint_from_int!(isize);
+
+impl From<u64> for BigInt {
+ #[inline]
+ fn from(n: u64) -> Self {
+ if n > 0 {
+ BigInt {
+ sign: Plus,
+ data: BigUint::from(n),
+ }
+ } else {
+ BigInt::zero()
+ }
+ }
+}
+
+impl From<u128> for BigInt {
+ #[inline]
+ fn from(n: u128) -> Self {
+ if n > 0 {
+ BigInt {
+ sign: Plus,
+ data: BigUint::from(n),
+ }
+ } else {
+ BigInt::zero()
+ }
+ }
+}
+
+macro_rules! impl_bigint_from_uint {
+ ($T:ty) => {
+ impl From<$T> for BigInt {
+ #[inline]
+ fn from(n: $T) -> Self {
+ BigInt::from(n as u64)
+ }
+ }
+ };
+}
+
+impl_bigint_from_uint!(u8);
+impl_bigint_from_uint!(u16);
+impl_bigint_from_uint!(u32);
+impl_bigint_from_uint!(usize);
+
+impl From<BigUint> for BigInt {
+ #[inline]
+ fn from(n: BigUint) -> Self {
+ if n.is_zero() {
+ BigInt::zero()
+ } else {
+ BigInt {
+ sign: Plus,
+ data: n,
+ }
+ }
+ }
+}
+
+impl ToBigInt for BigInt {
+ #[inline]
+ fn to_bigint(&self) -> Option<BigInt> {
+ Some(self.clone())
+ }
+}
+
+impl ToBigInt for BigUint {
+ #[inline]
+ fn to_bigint(&self) -> Option<BigInt> {
+ if self.is_zero() {
+ Some(Zero::zero())
+ } else {
+ Some(BigInt {
+ sign: Plus,
+ data: self.clone(),
+ })
+ }
+ }
+}
+
+impl ToBigUint for BigInt {
+ #[inline]
+ fn to_biguint(&self) -> Option<BigUint> {
+ match self.sign() {
+ Plus => Some(self.data.clone()),
+ NoSign => Some(Zero::zero()),
+ Minus => None,
+ }
+ }
+}
+
+#[cfg(has_try_from)]
+impl TryFrom<&BigInt> for BigUint {
+ type Error = TryFromBigIntError<()>;
+
+ #[inline]
+ fn try_from(value: &BigInt) -> Result<BigUint, TryFromBigIntError<()>> {
+ value
+ .to_biguint()
+ .ok_or_else(|| TryFromBigIntError::new(()))
+ }
+}
+
+#[cfg(has_try_from)]
+impl TryFrom<BigInt> for BigUint {
+ type Error = TryFromBigIntError<BigInt>;
+
+ #[inline]
+ fn try_from(value: BigInt) -> Result<BigUint, TryFromBigIntError<BigInt>> {
+ if value.sign() == Sign::Minus {
+ Err(TryFromBigIntError::new(value))
+ } else {
+ Ok(value.data)
+ }
+ }
+}
+
+macro_rules! impl_to_bigint {
+ ($T:ty, $from_ty:path) => {
+ impl ToBigInt for $T {
+ #[inline]
+ fn to_bigint(&self) -> Option<BigInt> {
+ $from_ty(*self)
+ }
+ }
+ };
+}
+
+impl_to_bigint!(isize, FromPrimitive::from_isize);
+impl_to_bigint!(i8, FromPrimitive::from_i8);
+impl_to_bigint!(i16, FromPrimitive::from_i16);
+impl_to_bigint!(i32, FromPrimitive::from_i32);
+impl_to_bigint!(i64, FromPrimitive::from_i64);
+impl_to_bigint!(i128, FromPrimitive::from_i128);
+
+impl_to_bigint!(usize, FromPrimitive::from_usize);
+impl_to_bigint!(u8, FromPrimitive::from_u8);
+impl_to_bigint!(u16, FromPrimitive::from_u16);
+impl_to_bigint!(u32, FromPrimitive::from_u32);
+impl_to_bigint!(u64, FromPrimitive::from_u64);
+impl_to_bigint!(u128, FromPrimitive::from_u128);
+
+impl_to_bigint!(f32, FromPrimitive::from_f32);
+impl_to_bigint!(f64, FromPrimitive::from_f64);
+
+impl From<bool> for BigInt {
+ fn from(x: bool) -> Self {
+ if x {
+ One::one()
+ } else {
+ Zero::zero()
+ }
+ }
+}
+
+#[inline]
+pub(super) fn from_signed_bytes_be(digits: &[u8]) -> BigInt {
+ let sign = match digits.first() {
+ Some(v) if *v > 0x7f => Sign::Minus,
+ Some(_) => Sign::Plus,
+ None => return BigInt::zero(),
+ };
+
+ if sign == Sign::Minus {
+ // two's-complement the content to retrieve the magnitude
+ let mut digits = Vec::from(digits);
+ twos_complement_be(&mut digits);
+ BigInt::from_biguint(sign, BigUint::from_bytes_be(&digits))
+ } else {
+ BigInt::from_biguint(sign, BigUint::from_bytes_be(digits))
+ }
+}
+
+#[inline]
+pub(super) fn from_signed_bytes_le(digits: &[u8]) -> BigInt {
+ let sign = match digits.last() {
+ Some(v) if *v > 0x7f => Sign::Minus,
+ Some(_) => Sign::Plus,
+ None => return BigInt::zero(),
+ };
+
+ if sign == Sign::Minus {
+ // two's-complement the content to retrieve the magnitude
+ let mut digits = Vec::from(digits);
+ twos_complement_le(&mut digits);
+ BigInt::from_biguint(sign, BigUint::from_bytes_le(&digits))
+ } else {
+ BigInt::from_biguint(sign, BigUint::from_bytes_le(digits))
+ }
+}
+
+#[inline]
+pub(super) fn to_signed_bytes_be(x: &BigInt) -> Vec<u8> {
+ let mut bytes = x.data.to_bytes_be();
+ let first_byte = bytes.first().cloned().unwrap_or(0);
+ if first_byte > 0x7f
+ && !(first_byte == 0x80 && bytes.iter().skip(1).all(Zero::is_zero) && x.sign == Sign::Minus)
+ {
+ // msb used by magnitude, extend by 1 byte
+ bytes.insert(0, 0);
+ }
+ if x.sign == Sign::Minus {
+ twos_complement_be(&mut bytes);
+ }
+ bytes
+}
+
+#[inline]
+pub(super) fn to_signed_bytes_le(x: &BigInt) -> Vec<u8> {
+ let mut bytes = x.data.to_bytes_le();
+ let last_byte = bytes.last().cloned().unwrap_or(0);
+ if last_byte > 0x7f
+ && !(last_byte == 0x80
+ && bytes.iter().rev().skip(1).all(Zero::is_zero)
+ && x.sign == Sign::Minus)
+ {
+ // msb used by magnitude, extend by 1 byte
+ bytes.push(0);
+ }
+ if x.sign == Sign::Minus {
+ twos_complement_le(&mut bytes);
+ }
+ bytes
+}
+
+/// Perform in-place two's complement of the given binary representation,
+/// in little-endian byte order.
+#[inline]
+fn twos_complement_le(digits: &mut [u8]) {
+ twos_complement(digits)
+}
+
+/// Perform in-place two's complement of the given binary representation
+/// in big-endian byte order.
+#[inline]
+fn twos_complement_be(digits: &mut [u8]) {
+ twos_complement(digits.iter_mut().rev())
+}
+
+/// Perform in-place two's complement of the given digit iterator
+/// starting from the least significant byte.
+#[inline]
+fn twos_complement<'a, I>(digits: I)
+where
+ I: IntoIterator<Item = &'a mut u8>,
+{
+ let mut carry = true;
+ for d in digits {
+ *d = !*d;
+ if carry {
+ *d = d.wrapping_add(1);
+ carry = d.is_zero();
+ }
+ }
+}