preserves/implementations/rust/preserves/src/value/signed_integer.rs

219 lines
6.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, 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<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<i32> for SignedInteger {
fn from(v: i32) -> Self {
SignedInteger(SignedIntegerRepr::I128(v.into()))
}
}
impl From<u32> for SignedInteger {
fn from(v: u32) -> Self {
SignedInteger(SignedIntegerRepr::I128(v.into()))
}
}
impl From<i64> for SignedInteger {
fn from(v: i64) -> Self {
SignedInteger(SignedIntegerRepr::I128(v.into()))
}
}
impl From<u64> for SignedInteger {
fn from(v: u64) -> Self {
SignedInteger(SignedIntegerRepr::I128(v.into()))
}
}
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 i32 {
type Error = ();
fn try_from(v: &SignedInteger) -> Result<Self, Self::Error> {
i128::try_from(v)?.try_into().map_err(|_| ())
}
}
impl TryFrom<&SignedInteger> for u32 {
type Error = ();
fn try_from(v: &SignedInteger) -> Result<Self, Self::Error> {
u128::try_from(v)?.try_into().map_err(|_| ())
}
}
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(|_| ())
}
}