preserves 5.0.0-rc.9

Implementation of the Preserves serialization format.
Documentation
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;

#[derive(Debug)]
pub struct OutOfRange(pub BigInt);

impl fmt::Display for OutOfRange {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "The value {:?} is out of range", &self.0)
    }
}

impl std::error::Error for OutOfRange {}

// 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
    }
}

//--

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 = OutOfRange;
            fn try_from(v: &SignedInteger) -> Result<Self, Self::Error> {
                i128::try_from(v)?.try_into().map_err(|_| OutOfRange(v.into()))
            }
        }

        impl TryFrom<&SignedInteger> for $uN {
            type Error = OutOfRange;
            fn try_from(v: &SignedInteger) -> Result<Self, Self::Error> {
                u128::try_from(v)?.try_into().map_err(|_| OutOfRange(v.into()))
            }
        }
    }
}

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<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 TryFrom<&SignedInteger> for i128 {
    type Error = OutOfRange;
    fn try_from(v: &SignedInteger) -> Result<Self, Self::Error> {
        match v.repr() {
            SignedIntegerRepr::I128(i) => Ok(*i),
            SignedIntegerRepr::U128(_) => Err(OutOfRange(v.into())),
            SignedIntegerRepr::Big(_) => Err(OutOfRange(v.into())),
        }
    }
}

impl TryFrom<&SignedInteger> for u128 {
    type Error = OutOfRange;
    fn try_from(v: &SignedInteger) -> Result<Self, Self::Error> {
        match v.repr() {
            SignedIntegerRepr::I128(i) => i.to_u128().ok_or_else(|| OutOfRange(v.into())),
            SignedIntegerRepr::U128(u) => Ok(*u),
            SignedIntegerRepr::Big(_) => Err(OutOfRange(v.into())),
        }
    }
}

//--

impl From<BigInt> 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<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<'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<isize> for SignedInteger {
    fn from(v: isize) -> Self {
        SignedInteger(SignedIntegerRepr::I128(v as i128))
    }
}

impl From<usize> for SignedInteger {
    fn from(v: usize) -> Self {
        if let Ok(w) = v.try_into() {
            SignedInteger(SignedIntegerRepr::I128(w))
        } else {
            SignedInteger(SignedIntegerRepr::U128(v as u128))
        }
    }
}

impl TryFrom<&SignedInteger> for isize {
    type Error = OutOfRange;
    fn try_from(v: &SignedInteger) -> Result<Self, Self::Error> {
        i128::try_from(v)?.try_into().map_err(|_| OutOfRange(v.into()))
    }
}

impl TryFrom<&SignedInteger> for usize {
    type Error = OutOfRange;
    fn try_from(v: &SignedInteger) -> Result<Self, Self::Error> {
        u128::try_from(v)?.try_into().map_err(|_| OutOfRange(v.into()))
    }
}