//! Representation of Preserves `SignedInteger`s as [i128]/[u128] (if they fit) or [BigInt] (if //! they don't). use num::bigint::BigInt; use num::traits::cast::ToPrimitive; use num::traits::sign::Signed; use std::borrow::Cow; use std::cmp::{Ord, Ordering, PartialOrd}; use std::convert::TryFrom; use std::convert::TryInto; use std::fmt; /// Internal representation of Preserves `SignedInteger`s. /// /// Invariant: if I128 can be used, it will be; otherwise, if U128 can be used, it will be; /// otherwise, Big will be used. #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub enum SignedIntegerRepr { I128(i128), U128(u128), Big(Box), } /// Main representation of Preserves `SignedInteger`s. #[derive(Clone, PartialEq, Eq, Hash)] pub struct SignedInteger(SignedIntegerRepr); impl fmt::Debug for SignedInteger { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { write!(f, "{}n", self) } } impl fmt::Display for SignedInteger { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { match self.repr() { SignedIntegerRepr::I128(i) => i.fmt(f), SignedIntegerRepr::U128(u) => u.fmt(f), SignedIntegerRepr::Big(n) => n.fmt(f), } } } impl Ord for SignedInteger { fn cmp(&self, other: &Self) -> Ordering { match self.repr() { SignedIntegerRepr::I128(i1) => match other.repr() { SignedIntegerRepr::I128(i2) => i1.cmp(i2), SignedIntegerRepr::U128(_) => { if *i1 < 0 { Ordering::Less } else { Ordering::Greater } } SignedIntegerRepr::Big(n) => { if n.is_negative() { Ordering::Less } else { Ordering::Greater } } }, SignedIntegerRepr::U128(u1) => match other.repr() { SignedIntegerRepr::I128(_) => Ordering::Greater, SignedIntegerRepr::U128(u2) => u1.cmp(u2), SignedIntegerRepr::Big(n) => { if n.is_positive() { Ordering::Less } else { Ordering::Greater } } }, SignedIntegerRepr::Big(n1) => match other.repr() { SignedIntegerRepr::I128(_) | SignedIntegerRepr::U128(_) => { if n1.is_negative() { Ordering::Less } else { Ordering::Greater } } SignedIntegerRepr::Big(n2) => n1.cmp(n2), }, } } } impl PartialOrd for SignedInteger { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } impl SignedInteger { /// Extract the internal representation. pub fn repr(&self) -> &SignedIntegerRepr { &self.0 } /// Does this `SignedInteger` fit in an [i128]? (See also [the TryFrom instance for /// i128](#impl-TryFrom<%26SignedInteger>-for-i128).) pub fn is_i(&self) -> bool { matches!(self.0, SignedIntegerRepr::I128(_)) } /// Does this `SignedInteger` fit in a [u128], but not an [i128]? (See also [the TryFrom /// instance for u128](#impl-TryFrom<%26SignedInteger>-for-u128).) pub fn is_u(&self) -> bool { matches!(self.0, SignedIntegerRepr::U128(_)) } /// Does this `SignedInteger` fit neither in a [u128] nor an [i128]? (See also [the TryFrom /// instance for BigInt](#impl-From<%26'a+SignedInteger>-for-BigInt).) pub fn is_big(&self) -> bool { matches!(self.0, SignedIntegerRepr::Big(_)) } } //-- macro_rules! map_integral_type_to_signed_integer { ($iN:ident, $uN:ident) => { impl From<$iN> for SignedInteger { fn from(v: $iN) -> Self { SignedInteger(SignedIntegerRepr::I128(v.into())) } } impl From<$uN> for SignedInteger { fn from(v: $uN) -> Self { SignedInteger(SignedIntegerRepr::I128(v.into())) } } impl TryFrom<&SignedInteger> for $iN { type Error = (); fn try_from(v: &SignedInteger) -> Result { i128::try_from(v)?.try_into().map_err(|_| ()) } } impl TryFrom<&SignedInteger> for $uN { type Error = (); fn try_from(v: &SignedInteger) -> Result { u128::try_from(v)?.try_into().map_err(|_| ()) } } }; } map_integral_type_to_signed_integer!(i8, u8); map_integral_type_to_signed_integer!(i16, u16); map_integral_type_to_signed_integer!(i32, u32); map_integral_type_to_signed_integer!(i64, u64); //-- impl From for SignedInteger { fn from(v: i128) -> Self { SignedInteger(SignedIntegerRepr::I128(v)) } } impl From for SignedInteger { fn from(v: u128) -> Self { if let Ok(w) = v.try_into() { SignedInteger(SignedIntegerRepr::I128(w)) } else { SignedInteger(SignedIntegerRepr::U128(v)) } } } impl TryFrom<&SignedInteger> for i128 { type Error = (); fn try_from(v: &SignedInteger) -> Result { match v.repr() { SignedIntegerRepr::I128(i) => Ok(*i), SignedIntegerRepr::U128(_) => Err(()), SignedIntegerRepr::Big(_) => Err(()), } } } impl TryFrom<&SignedInteger> for u128 { type Error = (); fn try_from(v: &SignedInteger) -> Result { match v.repr() { SignedIntegerRepr::I128(i) => i.to_u128().ok_or(()), SignedIntegerRepr::U128(u) => Ok(*u), SignedIntegerRepr::Big(_) => Err(()), } } } //-- impl From for SignedInteger { fn from(v: BigInt) -> Self { Self::from(Cow::Owned(v)) } } impl<'a> From<&'a SignedInteger> for BigInt { fn from(v: &'a SignedInteger) -> Self { match v.repr() { SignedIntegerRepr::I128(i) => BigInt::from(*i), SignedIntegerRepr::U128(u) => BigInt::from(*u), SignedIntegerRepr::Big(n) => *n.clone(), } } } //-- impl<'a> From> for SignedInteger { fn from(v: Cow<'a, BigInt>) -> Self { if let Some(w) = v.to_i128() { SignedInteger(SignedIntegerRepr::I128(w)) } else if let Some(w) = v.to_u128() { SignedInteger(SignedIntegerRepr::U128(w)) } else { SignedInteger(SignedIntegerRepr::Big(Box::new(v.into_owned()))) } } } impl<'a> From<&'a SignedInteger> for Cow<'a, BigInt> { fn from(v: &'a SignedInteger) -> Self { match v.repr() { SignedIntegerRepr::I128(i) => Cow::Owned(BigInt::from(*i)), SignedIntegerRepr::U128(u) => Cow::Owned(BigInt::from(*u)), SignedIntegerRepr::Big(n) => Cow::Borrowed(n), } } } //-- impl From for SignedInteger { fn from(v: isize) -> Self { SignedInteger(SignedIntegerRepr::I128(v as i128)) } } impl From for SignedInteger { fn from(v: usize) -> Self { SignedInteger(SignedIntegerRepr::U128(v as u128)) } } impl TryFrom<&SignedInteger> for isize { type Error = (); fn try_from(v: &SignedInteger) -> Result { i128::try_from(v)?.try_into().map_err(|_| ()) } } impl TryFrom<&SignedInteger> for usize { type Error = (); fn try_from(v: &SignedInteger) -> Result { u128::try_from(v)?.try_into().map_err(|_| ()) } }