use core::cmp::Ordering;
macro_rules! implfrom {
($( $(#[$($attr:meta)+])? $t:ident)+) => {
$(
$(#[$($attr)+])?
impl From<$t> for Integer {
#[inline]
fn from(value: $t) -> Self {
Self(value as _)
}
}
impl TryFrom<Integer> for $t {
type Error = core::num::TryFromIntError;
#[inline]
fn try_from(value: Integer) -> Result<Self, Self::Error> {
$t::try_from(value.0)
}
}
)+
};
}
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct Integer(i128);
impl Integer {
fn canonical_len(&self) -> usize {
let x = self.0;
if let Ok(x) = u8::try_from(x) {
if x < 24 {
1
} else {
2
}
} else if let Ok(x) = i8::try_from(x) {
if x >= -24i8 {
1
} else {
2
}
} else if u16::try_from(x).is_ok() || i16::try_from(x).is_ok() {
3
} else if u32::try_from(x).is_ok() || i32::try_from(x).is_ok() {
5
} else if u64::try_from(x).is_ok() || i64::try_from(x).is_ok() {
9
} else {
x.to_be_bytes().len() + 1
}
}
pub fn canonical_cmp(&self, other: &Self) -> Ordering {
match self.canonical_len().cmp(&other.canonical_len()) {
Ordering::Equal => {
match (self.0.is_negative(), other.0.is_negative()) {
(false, true) => Ordering::Less,
(true, false) => Ordering::Greater,
(true, true) => {
match self.0.cmp(&other.0) {
Ordering::Less => Ordering::Greater,
Ordering::Equal => Ordering::Equal,
Ordering::Greater => Ordering::Less,
}
}
(_, _) => self.0.cmp(&other.0),
}
}
x => x,
}
}
}
implfrom! {
u8 u16 u32 u64
i8 i16 i32 i64
#[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))]
usize
#[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))]
isize
}
impl TryFrom<i128> for Integer {
type Error = core::num::TryFromIntError;
#[inline]
fn try_from(value: i128) -> Result<Self, Self::Error> {
u64::try_from(match value.is_negative() {
false => value,
true => value ^ !0,
})?;
Ok(Integer(value))
}
}
impl TryFrom<u128> for Integer {
type Error = core::num::TryFromIntError;
#[inline]
fn try_from(value: u128) -> Result<Self, Self::Error> {
Ok(Self(u64::try_from(value)?.into()))
}
}
impl From<Integer> for i128 {
#[inline]
fn from(value: Integer) -> Self {
value.0
}
}
impl TryFrom<Integer> for u128 {
type Error = core::num::TryFromIntError;
#[inline]
fn try_from(value: Integer) -> Result<Self, Self::Error> {
u128::try_from(value.0)
}
}