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; // 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), } #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct SignedInteger(SignedIntegerRepr); 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 { pub fn repr(&self) -> &SignedIntegerRepr { &self.0 } pub fn is_i(&self) -> bool { matches!(self.0, SignedIntegerRepr::I128(_)) } pub fn is_u(&self) -> bool { matches!(self.0, SignedIntegerRepr::U128(_)) } pub fn is_big(&self) -> bool { matches!(self.0, SignedIntegerRepr::Big(_)) } } 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<'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 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<'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<'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 TryFrom<&SignedInteger> for i64 { type Error = (); fn try_from(v: &SignedInteger) -> Result { i128::try_from(v)?.try_into().map_err(|_| ()) } } impl TryFrom<&SignedInteger> for u64 { type Error = (); fn try_from(v: &SignedInteger) -> Result { u128::try_from(v)?.try_into().map_err(|_| ()) } } 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(|_| ()) } }