175 lines
5.2 KiB
Rust
175 lines
5.2 KiB
Rust
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<BigInt>),
|
|
}
|
|
|
|
#[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<Ordering> {
|
|
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<i128> for SignedInteger {
|
|
fn from(v: i128) -> Self {
|
|
SignedInteger(SignedIntegerRepr::I128(v))
|
|
}
|
|
}
|
|
|
|
impl From<u128> 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<Cow<'a, BigInt>> 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<Self, Self::Error> {
|
|
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<Self, Self::Error> {
|
|
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<Self, Self::Error> {
|
|
i128::try_from(v)?.try_into().map_err(|_| ())
|
|
}
|
|
}
|
|
|
|
impl TryFrom<&SignedInteger> for u64 {
|
|
type Error = ();
|
|
fn try_from(v: &SignedInteger) -> Result<Self, Self::Error> {
|
|
u128::try_from(v)?.try_into().map_err(|_| ())
|
|
}
|
|
}
|
|
|
|
impl TryFrom<&SignedInteger> for isize {
|
|
type Error = ();
|
|
fn try_from(v: &SignedInteger) -> Result<Self, Self::Error> {
|
|
i128::try_from(v)?.try_into().map_err(|_| ())
|
|
}
|
|
}
|
|
|
|
impl TryFrom<&SignedInteger> for usize {
|
|
type Error = ();
|
|
fn try_from(v: &SignedInteger) -> Result<Self, Self::Error> {
|
|
u128::try_from(v)?.try_into().map_err(|_| ())
|
|
}
|
|
}
|