af_utilities/types/
i256.rsuse std::cmp::Ordering;
use std::ops::{
Add,
AddAssign,
Div,
DivAssign,
Mul,
MulAssign,
Neg,
Rem,
RemAssign,
Sub,
SubAssign,
};
use af_sui_types::u256::U256;
use num_traits::{One, Zero};
use serde::{Deserialize, Serialize};
use super::errors::Error;
use super::onchain;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
pub struct I256(U256);
impl std::fmt::Display for I256 {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if self.is_neg() {
write!(f, "-{}", self.uabs())
} else {
write!(f, "{}", self.0)
}
}
}
macro_rules! impl_from_uint {
($($int:ty)*) => {
$(
impl From<$int> for I256 {
fn from(value: $int) -> Self {
Self(U256::from(value))
}
}
)*
};
}
impl_from_uint!(u8 u16 u32 u64 u128);
macro_rules! impl_from_int {
($($int:ty)*) => {
$(
impl From<$int> for I256 {
fn from(value: $int) -> Self {
let is_neg = value.is_negative();
let abs = Self::from(value.unsigned_abs());
match is_neg {
true => abs.neg(),
false => abs,
}
}
}
)*
};
}
impl_from_int!(i8 i16 i32 i64 i128);
macro_rules! impl_try_into_int {
($($bridge:ty => $int:ty),*) => {
$(
impl TryFrom<I256> for $int {
type Error = Error;
fn try_from(value: I256) -> Result<Self, Self::Error> {
let is_neg = value.is_neg();
let bridge: $bridge = value.uabs().try_into().map_err(|_| Error::Overflow)?;
let self_: Self = bridge.try_into().map_err(|_| Error::Overflow)?;
Ok(match is_neg {
true => -self_,
false => self_,
})
}
}
)*
};
}
impl_try_into_int!(u8 => i8, u16 => i16, u32 => i32, u64 => i64, u128 => i128);
macro_rules! impl_try_into_uint {
($($int:ty)*) => {
$(
impl TryFrom<I256> for $int {
type Error = Error;
fn try_from(value: I256) -> Result<Self, Self::Error> {
if value.is_neg() {
return Err(Error::Underflow);
}
value.uabs().try_into().map_err(|_| Error::Overflow)
}
}
)*
};
}
impl_try_into_uint!(u8 u16 u32 u64 u128);
impl TryFrom<U256> for I256 {
type Error = Error;
fn try_from(value: U256) -> Result<Self, Self::Error> {
if value <= onchain::max_i256() {
Ok(Self(value))
} else {
Err(Error::Overflow)
}
}
}
impl TryFrom<I256> for U256 {
type Error = Error;
fn try_from(value: I256) -> Result<Self, Self::Error> {
if value.is_neg() {
return Err(Error::Underflow);
}
Ok(value.0)
}
}
impl Add for I256 {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
let Self(x) = self;
let Self(y) = rhs;
let greatest_bit = Self::greatest_bit();
let not_greatest_bit = Self::not_greatest_bit();
let w = (x & not_greatest_bit) + (y & not_greatest_bit);
Self(if x ^ y < greatest_bit {
w
} else {
w ^ greatest_bit
})
}
}
impl Sub for I256 {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
let Self(x) = self;
let Self(y) = rhs;
let w = if x >= y {
x - y
} else {
((y - x) ^ Self::neg_one().0) + U256::one()
};
Self(w)
}
}
impl Mul for I256 {
type Output = Self;
fn mul(self, rhs: Self) -> Self::Output {
let z = self.uabs() * rhs.uabs();
let (Self(x), Self(y)) = (self, rhs);
let greatest_bit = Self::greatest_bit();
Self(if x ^ y < greatest_bit {
z
} else {
(greatest_bit - z) ^ greatest_bit
})
}
}
impl Div for I256 {
type Output = Self;
fn div(self, rhs: Self) -> Self::Output {
let z = self.uabs() / rhs.uabs();
let (Self(x), Self(y)) = (self, rhs);
let greatest_bit = Self::greatest_bit();
Self(if x ^ y < greatest_bit {
z
} else {
(greatest_bit - z) ^ greatest_bit
})
}
}
impl Rem for I256 {
type Output = Self;
fn rem(self, rhs: Self) -> Self::Output {
let is_neg = self.is_neg();
let abs_rem = Self(self.uabs() % rhs.uabs());
match is_neg {
true => abs_rem.neg(),
false => abs_rem,
}
}
}
super::reuse_op_for_assign!(I256 {
AddAssign add_assign +,
SubAssign sub_assign -,
MulAssign mul_assign *,
DivAssign div_assign /,
RemAssign rem_assign %,
});
impl PartialOrd for I256 {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for I256 {
fn cmp(&self, other: &Self) -> Ordering {
let Self(x) = self;
let Self(y) = other;
if x == y {
Ordering::Equal
} else if *x ^ Self::greatest_bit() < *y ^ Self::greatest_bit() {
Ordering::Less
} else {
Ordering::Greater
}
}
}
impl Neg for I256 {
type Output = Self;
fn neg(self) -> Self::Output {
Self(((self.0 ^ Self::not_greatest_bit()) + U256::one()) ^ Self::greatest_bit())
}
}
impl One for I256 {
fn one() -> Self {
Self::one()
}
}
impl Zero for I256 {
fn zero() -> Self {
Self(U256::zero())
}
fn is_zero(&self) -> bool {
self.0 == U256::zero()
}
}
impl I256 {
fn greatest_bit() -> U256 {
U256::one() << 255_u8
}
fn not_greatest_bit() -> U256 {
(U256::one() << 255_u8) - U256::one()
}
pub const fn neg_one() -> Self {
Self(U256::max_value())
}
pub const fn into_inner(self) -> U256 {
self.0
}
pub const fn from_inner(inner: U256) -> Self {
Self(inner)
}
pub const fn one() -> Self {
Self(U256::one())
}
pub const fn zero() -> Self {
Self(U256::zero())
}
pub fn is_neg(&self) -> bool {
self.0 >= Self::greatest_bit()
}
pub fn uabs(&self) -> U256 {
let Self(x) = self;
if *x >= Self::greatest_bit() {
(*x ^ Self::neg_one().0) + U256::one()
} else {
*x
}
}
pub fn abs(self) -> Self {
let Self(x) = self;
let greatest_bit = Self::greatest_bit();
let not_greatest_bit = Self::not_greatest_bit();
Self(if x >= greatest_bit {
((x ^ not_greatest_bit) + U256::one()) ^ greatest_bit
} else {
x
})
}
}
#[cfg(test)]
#[allow(clippy::unwrap_used)]
mod tests {
use super::*;
#[test]
fn from_u128_max_doesnt_overflow() {
assert!(!I256::from(u128::MAX).is_neg())
}
#[test]
fn from_i128_min_doesnt_underflow() {
assert!(I256::from(i128::MIN).is_neg())
}
}