use crate::errors::{ParseI256Error, TryFromBigIntError};
use serde::{Deserialize, Serialize};
use std::cmp;
use std::convert::{TryFrom, TryInto};
use std::fmt;
use std::iter;
use std::ops;
use std::str;
use std::{i128, i64, u64};
use web3::types::U256;
fn twos_complement(u: U256) -> U256 {
let (twos_complement, _) = (!u).overflowing_add(U256::one());
twos_complement
}
#[inline(always)]
fn handle_overflow<T>((result, overflow): (T, bool)) -> T {
#[cfg(debug_assertions)]
{
assert!(!overflow, "overflow");
}
let _ = overflow;
result
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum Sign {
Positive,
Negative,
}
impl Sign {
fn from_signum64(sign: i64) -> Self {
match sign {
0 | 1 => Sign::Positive,
-1 => Sign::Negative,
_ => unreachable!(),
}
}
}
#[derive(Clone, Copy, Default, Deserialize, Eq, Hash, PartialEq, Serialize)]
#[serde(transparent)]
pub struct I256(U256);
impl I256 {
pub const MAX: I256 = I256(U256([u64::MAX, u64::MAX, u64::MAX, i64::MAX as _]));
pub const MIN: I256 = I256(U256([0, 0, 0, i64::MIN as _]));
pub const fn zero() -> Self {
I256(U256([0, 0, 0, 0]))
}
pub const fn one() -> Self {
I256(U256([1, 0, 0, 0]))
}
pub const fn minus_one() -> Self {
I256(U256([u64::MAX, u64::MAX, u64::MAX, u64::MAX]))
}
pub const fn max_value() -> Self {
I256::MAX
}
pub const fn min_value() -> Self {
I256::MIN
}
fn overflowing_from_sign_and_abs(sign: Sign, abs: U256) -> (Self, bool) {
let value = I256(match sign {
Sign::Positive => abs,
Sign::Negative => twos_complement(abs),
});
(value, value.sign() != sign)
}
fn checked_from_sign_and_abs(sign: Sign, abs: U256) -> Option<Self> {
let (result, overflow) = I256::overflowing_from_sign_and_abs(sign, abs);
if overflow {
None
} else {
Some(result)
}
}
fn into_sign_and_abs(self) -> (Sign, U256) {
let sign = self.sign();
let abs = match sign {
Sign::Positive => self.0,
Sign::Negative => twos_complement(self.0),
};
(sign, abs)
}
fn sign(self) -> Sign {
let most_significant_word = (self.0).0[3];
match most_significant_word & (1 << 63) {
0 => Sign::Positive,
_ => Sign::Negative,
}
}
#[must_use]
pub fn from_raw(raw: U256) -> Self {
I256(raw)
}
#[must_use]
pub fn into_raw(self) -> U256 {
self.0
}
#[must_use]
pub fn low_i32(&self) -> i32 {
self.0.low_u32() as _
}
#[must_use]
pub fn low_u32(&self) -> u32 {
self.0.low_u32()
}
#[must_use]
pub fn low_i64(&self) -> i64 {
self.0.low_u64() as _
}
#[must_use]
pub fn low_u64(&self) -> u64 {
self.0.low_u64() as _
}
#[must_use]
pub fn low_i128(&self) -> i128 {
self.0.low_u128() as _
}
#[must_use]
pub fn low_u128(&self) -> u128 {
self.0.low_u128() as _
}
#[must_use]
pub fn low_isize(&self) -> isize {
self.0.low_u64() as _
}
#[must_use]
pub fn low_usize(&self) -> usize {
self.0.low_u64() as _
}
#[must_use]
pub fn as_i32(&self) -> i32 {
(*self).try_into().unwrap()
}
#[must_use]
pub fn as_u32(&self) -> u32 {
(*self).try_into().unwrap()
}
#[must_use]
pub fn as_i64(&self) -> i64 {
(*self).try_into().unwrap()
}
#[must_use]
pub fn as_u64(&self) -> u64 {
(*self).try_into().unwrap()
}
#[must_use]
pub fn as_i128(&self) -> i128 {
(*self).try_into().unwrap()
}
#[must_use]
pub fn as_u128(&self) -> u128 {
(*self).try_into().unwrap()
}
#[must_use]
pub fn as_isize(&self) -> usize {
(*self).try_into().unwrap()
}
#[must_use]
pub fn as_usize(&self) -> usize {
(*self).try_into().unwrap()
}
pub fn from_dec_str(value: &str) -> Result<Self, ParseI256Error> {
let (sign, value) = match value.as_bytes().first() {
Some(b'+') => (Sign::Positive, &value[1..]),
Some(b'-') => (Sign::Negative, &value[1..]),
_ => (Sign::Positive, value),
};
let abs = U256::from_dec_str(value)?;
let result =
I256::checked_from_sign_and_abs(sign, abs).ok_or(ParseI256Error::IntegerOverflow)?;
Ok(result)
}
pub fn from_hex_str(value: &str) -> Result<Self, ParseI256Error> {
let (sign, value) = match value.as_bytes().first() {
Some(b'+') => (Sign::Positive, &value[1..]),
Some(b'-') => (Sign::Negative, &value[1..]),
_ => (Sign::Positive, value),
};
if value.len() > 64 {
return Err(ParseI256Error::IntegerOverflow);
}
let mut abs = U256::zero();
for (i, word) in value.as_bytes().rchunks(16).enumerate() {
let word = str::from_utf8(word).map_err(|_| ParseI256Error::InvalidDigit)?;
abs.0[i] = u64::from_str_radix(word, 16).map_err(|_| ParseI256Error::InvalidDigit)?;
}
let result =
I256::checked_from_sign_and_abs(sign, abs).ok_or(ParseI256Error::IntegerOverflow)?;
Ok(result)
}
#[must_use]
pub fn signum(self) -> Self {
self.signum64().into()
}
fn signum64(self) -> i64 {
match self.sign() {
Sign::Positive => (!self.is_zero()).into(),
Sign::Negative => -1,
}
}
#[must_use]
pub fn is_positive(self) -> bool {
self.signum64().is_positive()
}
#[must_use]
pub fn is_negative(self) -> bool {
self.signum64().is_negative()
}
#[must_use]
pub fn is_zero(self) -> bool {
self.0.is_zero()
}
#[must_use]
pub fn abs(self) -> Self {
handle_overflow(self.overflowing_abs())
}
#[must_use]
pub fn overflowing_abs(self) -> (Self, bool) {
if self == I256::MIN {
(self, true)
} else {
(I256(self.abs_unsigned()), false)
}
}
#[must_use]
pub fn checked_abs(self) -> Option<Self> {
let (result, overflow) = self.overflowing_abs();
if overflow {
None
} else {
Some(result)
}
}
#[must_use]
pub fn saturating_abs(self) -> Self {
self.checked_abs().unwrap_or(I256::MAX)
}
#[must_use]
pub fn wrapping_abs(self) -> Self {
let (result, _) = self.overflowing_abs();
result
}
fn abs_unsigned(self) -> U256 {
let (_, abs) = self.into_sign_and_abs();
abs
}
#[must_use]
pub fn overflowing_neg(self) -> (Self, bool) {
if self == I256::MIN {
(self, true)
} else {
(I256(twos_complement(self.0)), false)
}
}
#[must_use]
pub fn checked_neg(self) -> Option<Self> {
let (result, overflow) = self.overflowing_neg();
if overflow {
None
} else {
Some(result)
}
}
#[must_use]
pub fn saturating_neg(self) -> Self {
self.checked_neg().unwrap_or(I256::MAX)
}
#[must_use]
pub fn wrapping_neg(self) -> Self {
let (result, _) = self.overflowing_neg();
result
}
#[must_use]
pub fn bits(&self) -> u32 {
let unsigned = self.abs_unsigned();
let unsigned_bits = unsigned.bits();
let bits = if self.count_zeros() == self.trailing_zeros() {
unsigned_bits
} else {
unsigned_bits + 1
};
bits as _
}
#[must_use]
pub fn bit(&self, index: usize) -> bool {
self.0.bit(index)
}
#[must_use]
pub fn count_ones(&self) -> u32 {
(self.0).0.iter().map(|word| word.count_ones()).sum()
}
#[must_use]
pub fn count_zeros(&self) -> u32 {
(self.0).0.iter().map(|word| word.count_zeros()).sum()
}
#[must_use]
pub fn leading_zeros(&self) -> u32 {
self.0.leading_zeros()
}
#[must_use]
pub fn trailing_zeros(&self) -> u32 {
self.0.trailing_zeros()
}
#[must_use]
pub fn byte(&self, index: usize) -> u8 {
self.0.byte(index)
}
#[allow(clippy::wrong_self_convention)]
pub fn to_big_endian(&self, bytes: &mut [u8]) {
self.0.to_big_endian(bytes)
}
#[allow(clippy::wrong_self_convention)]
pub fn to_little_endian(&self, bytes: &mut [u8]) {
self.0.to_little_endian(bytes)
}
#[must_use]
pub fn overflowing_add(self, rhs: Self) -> (Self, bool) {
let (unsigned, _) = self.0.overflowing_add(rhs.0);
let result = I256(unsigned);
let overflow = matches!(
(self.sign(), rhs.sign(), result.sign()),
(Sign::Positive, Sign::Positive, Sign::Negative)
| (Sign::Negative, Sign::Negative, Sign::Positive)
);
(result, overflow)
}
#[must_use]
pub fn checked_add(self, other: Self) -> Option<Self> {
let (result, overflow) = self.overflowing_add(other);
if overflow {
None
} else {
Some(result)
}
}
#[must_use]
pub fn saturating_add(self, other: Self) -> Self {
let (result, overflow) = self.overflowing_add(other);
if overflow {
match result.sign() {
Sign::Positive => I256::MIN,
Sign::Negative => I256::MAX,
}
} else {
result
}
}
#[must_use]
pub fn wrapping_add(self, other: Self) -> Self {
let (result, _) = self.overflowing_add(other);
result
}
#[must_use]
pub fn overflowing_sub(self, rhs: Self) -> (Self, bool) {
let (unsigned, _) = self.0.overflowing_sub(rhs.0);
let result = I256(unsigned);
let overflow = matches!(
(self.sign(), rhs.sign(), result.sign()),
(Sign::Positive, Sign::Negative, Sign::Negative)
| (Sign::Negative, Sign::Positive, Sign::Positive)
);
(result, overflow)
}
#[must_use]
pub fn checked_sub(self, other: Self) -> Option<Self> {
let (result, overflow) = self.overflowing_sub(other);
if overflow {
None
} else {
Some(result)
}
}
#[must_use]
pub fn saturating_sub(self, other: Self) -> Self {
let (result, overflow) = self.overflowing_sub(other);
if overflow {
match result.sign() {
Sign::Positive => I256::MIN,
Sign::Negative => I256::MAX,
}
} else {
result
}
}
#[must_use]
pub fn wrapping_sub(self, other: Self) -> Self {
let (result, _) = self.overflowing_sub(other);
result
}
#[must_use]
pub fn overflowing_mul(self, rhs: Self) -> (Self, bool) {
let sign = Sign::from_signum64(self.signum64() * rhs.signum64());
let (unsigned, overflow_mul) = self.abs_unsigned().overflowing_mul(rhs.abs_unsigned());
let (result, overflow_conv) = I256::overflowing_from_sign_and_abs(sign, unsigned);
(result, overflow_mul || overflow_conv)
}
#[must_use]
pub fn checked_mul(self, other: Self) -> Option<Self> {
let (result, overflow) = self.overflowing_mul(other);
if overflow {
None
} else {
Some(result)
}
}
#[must_use]
pub fn saturating_mul(self, rhs: Self) -> Self {
self.checked_mul(rhs).unwrap_or_else(|| {
match Sign::from_signum64(self.signum64() * rhs.signum64()) {
Sign::Positive => I256::MAX,
Sign::Negative => I256::MIN,
}
})
}
#[must_use]
pub fn wrapping_mul(self, rhs: Self) -> Self {
let (result, _) = self.overflowing_mul(rhs);
result
}
#[must_use]
pub fn overflowing_div(self, rhs: Self) -> (Self, bool) {
let sign = Sign::from_signum64(self.signum64() / rhs.signum64());
let unsigned = self.abs_unsigned() / rhs.abs_unsigned();
let (result, overflow_conv) = I256::overflowing_from_sign_and_abs(sign, unsigned);
(result, overflow_conv && !result.is_zero())
}
#[must_use]
pub fn checked_div(self, rhs: Self) -> Option<Self> {
if rhs == I256::zero() || (self == Self::min_value() && rhs == -I256::one()) {
None
} else {
Some(self.overflowing_div(rhs).0)
}
}
#[must_use]
pub fn saturating_div(self, rhs: Self) -> Self {
self.checked_div(rhs).unwrap_or(I256::MAX)
}
#[must_use]
pub fn wrapping_div(self, rhs: Self) -> Self {
self.overflowing_div(rhs).0
}
#[must_use]
pub fn overflowing_rem(self, rhs: Self) -> (Self, bool) {
if self == Self::MIN && rhs == Self::from(-1) {
(Self::zero(), true)
} else {
let div_res = self / rhs;
(self - div_res * rhs, false)
}
}
#[must_use]
pub fn checked_rem(self, rhs: Self) -> Option<Self> {
if rhs == I256::zero() || (self == Self::min_value() && rhs == -I256::one()) {
None
} else {
Some(self.overflowing_rem(rhs).0)
}
}
#[must_use]
pub fn wrapping_rem(self, rhs: Self) -> Self {
self.overflowing_rem(rhs).0
}
#[must_use]
pub fn div_euclid(self, rhs: Self) -> Self {
let q = self / rhs;
if (self % rhs).is_negative() {
return if rhs.is_positive() {
q - I256::one()
} else {
q + I256::one()
};
}
q
}
#[must_use]
pub fn rem_euclid(self, rhs: Self) -> Self {
let r = self % rhs;
if r < Self::zero() {
if rhs < Self::zero() {
r - rhs
} else {
r + rhs
}
} else {
r
}
}
#[must_use]
pub fn overflowing_div_euclid(self, rhs: Self) -> (Self, bool) {
if self == Self::min_value() && rhs == -I256::one() {
(self, true)
} else {
(self.div_euclid(rhs), false)
}
}
#[must_use]
pub fn checked_div_euclid(self, rhs: Self) -> Option<Self> {
if rhs == I256::zero() || (self == Self::min_value() && rhs == -I256::one()) {
None
} else {
Some(self.div_euclid(rhs))
}
}
#[must_use]
pub fn wrapping_div_euclid(self, rhs: Self) -> Self {
self.overflowing_div_euclid(rhs).0
}
#[must_use]
pub fn overflowing_rem_euclid(self, rhs: Self) -> (Self, bool) {
if self == Self::min_value() && rhs == -Self::one() {
(Self::zero(), true)
} else {
(self.rem_euclid(rhs), false)
}
}
#[must_use]
pub fn wrapping_rem_euclid(self, rhs: Self) -> Self {
self.overflowing_rem_euclid(rhs).0
}
#[must_use]
pub fn checked_rem_euclid(self, rhs: Self) -> Option<Self> {
if rhs == I256::zero() || (self == Self::min_value() && rhs == -I256::one()) {
None
} else {
Some(self.rem_euclid(rhs))
}
}
fn pow_sign(self, exp: u32) -> Sign {
let is_exp_odd = exp % 2 != 0;
if is_exp_odd && self.is_negative() {
Sign::Negative
} else {
Sign::Positive
}
}
#[must_use]
pub fn exp10(n: usize) -> Self {
U256::exp10(n).try_into().expect("overflow")
}
#[must_use]
pub fn pow(self, exp: u32) -> Self {
handle_overflow(self.overflowing_pow(exp))
}
#[must_use]
pub fn overflowing_pow(self, exp: u32) -> (Self, bool) {
let sign = self.pow_sign(exp);
let (unsigned, overflow_pow) = self.abs_unsigned().overflowing_pow(exp.into());
let (result, overflow_conv) = I256::overflowing_from_sign_and_abs(sign, unsigned);
(result, overflow_pow || overflow_conv)
}
#[must_use]
pub fn checked_pow(self, exp: u32) -> Option<Self> {
let (result, overflow) = self.overflowing_pow(exp);
if overflow {
None
} else {
Some(result)
}
}
#[must_use]
pub fn saturating_pow(self, exp: u32) -> Self {
let (result, overflow) = self.overflowing_pow(exp);
if overflow {
match self.pow_sign(exp) {
Sign::Positive => I256::MAX,
Sign::Negative => I256::MIN,
}
} else {
result
}
}
#[must_use]
pub fn wrapping_pow(self, exp: u32) -> Self {
let (result, _) = self.overflowing_pow(exp);
result
}
}
macro_rules! impl_from {
($( $t:ty ),*) => {
$(
impl From<$t> for I256 {
fn from(value: $t) -> Self {
#[allow(unused_comparisons)]
I256(if value < 0 {
let abs = (!(value as u128)).wrapping_add(1);
twos_complement(U256::from(abs))
} else {
U256::from(value)
})
}
}
impl TryFrom<I256> for $t {
type Error = TryFromBigIntError;
fn try_from(value: I256) -> Result<Self, Self::Error> {
if value < I256::from(Self::min_value()) ||
value > I256::from(Self::max_value()) {
return Err(TryFromBigIntError);
}
Ok(value.0.low_u128() as _)
}
}
)*
};
}
impl_from!(i8, u8, i16, u16, i32, u32, i64, u64, i128, u128, isize, usize);
impl TryFrom<U256> for I256 {
type Error = TryFromBigIntError;
fn try_from(from: U256) -> Result<Self, Self::Error> {
let value = I256(from);
match value.sign() {
Sign::Positive => Ok(value),
Sign::Negative => Err(TryFromBigIntError),
}
}
}
impl TryFrom<I256> for U256 {
type Error = TryFromBigIntError;
fn try_from(value: I256) -> Result<Self, Self::Error> {
match value.sign() {
Sign::Positive => Ok(value.0),
Sign::Negative => Err(TryFromBigIntError),
}
}
}
impl str::FromStr for I256 {
type Err = ParseI256Error;
fn from_str(value: &str) -> Result<Self, Self::Err> {
I256::from_hex_str(value)
}
}
impl fmt::Debug for I256 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(self, f)
}
}
impl fmt::Display for Sign {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match (self, f.sign_plus()) {
(Sign::Positive, false) => Ok(()),
(Sign::Positive, true) => write!(f, "+"),
(Sign::Negative, _) => write!(f, "-"),
}
}
}
impl fmt::Display for I256 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let (sign, abs) = self.into_sign_and_abs();
sign.fmt(f)?;
write!(f, "{}", abs)
}
}
impl fmt::LowerHex for I256 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let (sign, abs) = self.into_sign_and_abs();
fmt::Display::fmt(&sign, f)?;
write!(f, "{:x}", abs)
}
}
impl fmt::UpperHex for I256 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let (sign, abs) = self.into_sign_and_abs();
fmt::Display::fmt(&sign, f)?;
let mut buffer = format!("{:x}", abs);
buffer.make_ascii_uppercase();
write!(f, "{}", buffer)
}
}
impl cmp::PartialOrd for I256 {
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
Some(self.cmp(other))
}
}
impl cmp::Ord for I256 {
fn cmp(&self, other: &Self) -> cmp::Ordering {
use cmp::Ordering::*;
use Sign::*;
match (self.into_sign_and_abs(), other.into_sign_and_abs()) {
((Positive, _), (Negative, _)) => Greater,
((Negative, _), (Positive, _)) => Less,
((Positive, this), (Positive, other)) => this.cmp(&other),
((Negative, this), (Negative, other)) => other.cmp(&this),
}
}
}
impl ops::Neg for I256 {
type Output = I256;
fn neg(self) -> Self::Output {
handle_overflow(self.overflowing_neg())
}
}
impl ops::Not for I256 {
type Output = I256;
fn not(self) -> Self::Output {
I256(!self.0)
}
}
impl ops::BitAnd for I256 {
type Output = Self;
fn bitand(self, rhs: Self) -> Self::Output {
I256(self.0 & rhs.0)
}
}
impl ops::BitAndAssign for I256 {
fn bitand_assign(&mut self, rhs: Self) {
*self = *self & rhs;
}
}
impl ops::BitOr for I256 {
type Output = Self;
fn bitor(self, rhs: Self) -> Self::Output {
I256(self.0 | rhs.0)
}
}
impl ops::BitOrAssign for I256 {
fn bitor_assign(&mut self, rhs: Self) {
*self = *self | rhs;
}
}
impl ops::BitXor for I256 {
type Output = Self;
fn bitxor(self, rhs: Self) -> Self::Output {
I256(self.0 ^ rhs.0)
}
}
impl ops::BitXorAssign for I256 {
fn bitxor_assign(&mut self, rhs: Self) {
*self = *self ^ rhs;
}
}
macro_rules! impl_shift {
($( $t:ty $( [ $convert:ident ] )? ),*) => {
$(
impl_shift!(__impl $t $([$convert])*);
)*
};
(__impl $t:ty) => {
impl_shift!(__impl $t [ from ]);
};
(__impl $t:ty [ $convert:ident ]) => {
impl ops::Shl<$t> for I256 {
type Output = Self;
fn shl(self, rhs: $t) -> Self::Output {
I256(self.0 << I256::$convert(rhs).0)
}
}
impl ops::ShlAssign<$t> for I256 {
fn shl_assign(&mut self, rhs: $t) {
*self = *self << rhs;
}
}
impl ops::Shr<$t> for I256 {
type Output = Self;
fn shr(self, rhs: $t) -> Self::Output {
I256(self.0 >> I256::$convert(rhs).0)
}
}
impl ops::ShrAssign<$t> for I256 {
fn shr_assign(&mut self, rhs: $t) {
*self = *self >> rhs;
}
}
};
}
impl_shift!(i8, u8, i16, u16, i32, u32, i64, u64, i128, u128, isize, usize);
impl_shift!(I256, U256[from_raw]);
impl ops::Add for I256 {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
handle_overflow(self.overflowing_add(rhs))
}
}
impl ops::AddAssign for I256 {
fn add_assign(&mut self, rhs: Self) {
*self = *self + rhs
}
}
impl ops::Sub for I256 {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
handle_overflow(self.overflowing_sub(rhs))
}
}
impl ops::SubAssign for I256 {
fn sub_assign(&mut self, rhs: Self) {
*self = *self - rhs;
}
}
impl ops::Mul for I256 {
type Output = Self;
fn mul(self, rhs: Self) -> Self::Output {
handle_overflow(self.overflowing_mul(rhs))
}
}
impl ops::MulAssign for I256 {
fn mul_assign(&mut self, rhs: Self) {
*self = *self * rhs;
}
}
impl ops::Div for I256 {
type Output = Self;
fn div(self, rhs: Self) -> Self::Output {
handle_overflow(self.overflowing_div(rhs))
}
}
impl ops::DivAssign for I256 {
fn div_assign(&mut self, rhs: Self) {
*self = *self / rhs;
}
}
impl ops::Rem for I256 {
type Output = Self;
fn rem(self, rhs: Self) -> Self::Output {
handle_overflow(self.overflowing_rem(rhs))
}
}
impl ops::RemAssign for I256 {
fn rem_assign(&mut self, rhs: Self) {
*self = *self % rhs;
}
}
impl iter::Sum for I256 {
fn sum<I>(iter: I) -> Self
where
I: Iterator<Item = Self>,
{
iter.fold(I256::zero(), |acc, x| acc + x)
}
}
impl iter::Product for I256 {
fn product<I>(iter: I) -> Self
where
I: Iterator<Item = Self>,
{
iter.fold(I256::one(), |acc, x| acc * x)
}
}
#[cfg(test)]
mod tests {
use super::*;
use lazy_static::lazy_static;
use serde_json::json;
lazy_static! {
static ref MIN_ABS: U256 = U256::from(1) << 255;
}
#[test]
fn identities() {
assert_eq!(I256::zero().to_string(), "0");
assert_eq!(I256::one().to_string(), "1");
assert_eq!(I256::minus_one().to_string(), "-1");
assert_eq!(
I256::max_value().to_string(),
"57896044618658097711785492504343953926634992332820282019728792003956564819967"
);
assert_eq!(
I256::min_value().to_string(),
"-57896044618658097711785492504343953926634992332820282019728792003956564819968"
);
}
#[test]
#[allow(clippy::cognitive_complexity)]
fn std_num_conversion() {
let small_positive = I256::from(42);
let small_negative = I256::from(-42);
let large_positive =
I256::from_dec_str("314159265358979323846264338327950288419716").unwrap();
let large_negative =
I256::from_dec_str("-314159265358979323846264338327950288419716").unwrap();
let large_unsigned =
U256::from_dec_str("314159265358979323846264338327950288419716").unwrap();
macro_rules! assert_from {
($signed:ty, $unsigned:ty) => {
assert_eq!(I256::from(-42 as $signed).to_string(), "-42");
assert_eq!(I256::from(42 as $signed).to_string(), "42");
assert_eq!(
I256::from(<$signed>::max_value()).to_string(),
<$signed>::max_value().to_string(),
);
assert_eq!(
I256::from(<$signed>::min_value()).to_string(),
<$signed>::min_value().to_string(),
);
assert_eq!(I256::from(42 as $unsigned).to_string(), "42");
assert_eq!(
I256::from(<$unsigned>::max_value()).to_string(),
<$unsigned>::max_value().to_string(),
);
assert!(matches!(<$signed>::try_from(small_positive), Ok(42)));
assert!(matches!(<$signed>::try_from(small_negative), Ok(-42)));
assert!(matches!(<$signed>::try_from(large_positive), Err(_)));
assert!(matches!(<$signed>::try_from(large_negative), Err(_)));
assert!(matches!(<$unsigned>::try_from(small_positive), Ok(42)));
assert!(matches!(<$unsigned>::try_from(small_negative), Err(_)));
assert!(matches!(<$unsigned>::try_from(large_positive), Err(_)));
assert!(matches!(<$unsigned>::try_from(large_negative), Err(_)));
};
}
assert_eq!(I256::from(0).to_string(), "0");
assert_from!(i8, u8);
assert_from!(i16, u16);
assert_from!(i32, u32);
assert_from!(i64, u64);
assert_from!(i128, u128);
assert_eq!(I256::try_from(large_unsigned).unwrap(), large_positive);
assert_eq!(U256::try_from(large_positive).unwrap(), large_unsigned);
assert!(I256::try_from(U256::MAX).is_err());
assert!(U256::try_from(small_negative).is_err());
assert!(U256::try_from(large_negative).is_err());
}
#[test]
fn parse_dec_str() {
let unsigned = U256::from_dec_str("314159265358979323846264338327950288419716").unwrap();
let value = I256::from_dec_str(&format!("-{}", unsigned)).unwrap();
assert_eq!(value.into_sign_and_abs(), (Sign::Negative, unsigned));
let value = I256::from_dec_str(&format!("{}", unsigned)).unwrap();
assert_eq!(value.into_sign_and_abs(), (Sign::Positive, unsigned));
let value = I256::from_dec_str(&format!("+{}", unsigned)).unwrap();
assert_eq!(value.into_sign_and_abs(), (Sign::Positive, unsigned));
let err = I256::from_dec_str("invalid string").unwrap_err();
assert!(matches!(err, ParseI256Error::InvalidDigit));
let err = I256::from_dec_str(&format!("1{}", U256::MAX)).unwrap_err();
assert!(matches!(err, ParseI256Error::IntegerOverflow));
let err = I256::from_dec_str(&format!("-{}", U256::MAX)).unwrap_err();
assert!(matches!(err, ParseI256Error::IntegerOverflow));
let value = I256::from_dec_str(&format!("-{}", *MIN_ABS)).unwrap();
assert_eq!(value.into_sign_and_abs(), (Sign::Negative, *MIN_ABS));
let err = I256::from_dec_str(&format!("{}", *MIN_ABS)).unwrap_err();
assert!(matches!(err, ParseI256Error::IntegerOverflow));
}
#[test]
fn parse_hex_str() {
let unsigned = U256::from_dec_str("314159265358979323846264338327950288419716").unwrap();
let value = I256::from_hex_str(&format!("-{:x}", unsigned)).unwrap();
assert_eq!(value.into_sign_and_abs(), (Sign::Negative, unsigned));
let value = I256::from_hex_str(&format!("{:x}", unsigned)).unwrap();
assert_eq!(value.into_sign_and_abs(), (Sign::Positive, unsigned));
let value = I256::from_hex_str(&format!("+{:x}", unsigned)).unwrap();
assert_eq!(value.into_sign_and_abs(), (Sign::Positive, unsigned));
let err = I256::from_hex_str("invalid string").unwrap_err();
assert!(matches!(err, ParseI256Error::InvalidDigit));
let err = I256::from_hex_str(&format!("1{:x}", U256::MAX)).unwrap_err();
assert!(matches!(err, ParseI256Error::IntegerOverflow));
let err = I256::from_hex_str(&format!("-{:x}", U256::MAX)).unwrap_err();
assert!(matches!(err, ParseI256Error::IntegerOverflow));
let value = I256::from_hex_str(&format!("-{:x}", *MIN_ABS)).unwrap();
assert_eq!(value.into_sign_and_abs(), (Sign::Negative, *MIN_ABS));
let err = I256::from_hex_str(&format!("{:x}", *MIN_ABS)).unwrap_err();
assert!(matches!(err, ParseI256Error::IntegerOverflow));
}
#[test]
fn formatting() {
let unsigned = U256::from_dec_str("314159265358979323846264338327950288419716").unwrap();
let positive = I256::try_from(unsigned).unwrap();
let negative = -positive;
assert_eq!(format!("{}", positive), format!("{}", unsigned));
assert_eq!(format!("{}", negative), format!("-{}", unsigned));
assert_eq!(format!("{:+}", positive), format!("+{}", unsigned));
assert_eq!(format!("{:+}", negative), format!("-{}", unsigned));
assert_eq!(format!("{:x}", positive), format!("{:x}", unsigned));
assert_eq!(format!("{:x}", negative), format!("-{:x}", unsigned));
assert_eq!(format!("{:+x}", positive), format!("+{:x}", unsigned));
assert_eq!(format!("{:+x}", negative), format!("-{:x}", unsigned));
assert_eq!(
format!("{:X}", positive),
format!("{:x}", unsigned).to_uppercase()
);
assert_eq!(
format!("{:X}", negative),
format!("-{:x}", unsigned).to_uppercase()
);
assert_eq!(
format!("{:+X}", positive),
format!("+{:x}", unsigned).to_uppercase()
);
assert_eq!(
format!("{:+X}", negative),
format!("-{:x}", unsigned).to_uppercase()
);
}
#[test]
fn signs() {
assert_eq!(I256::MAX.signum(), I256::one());
assert!(I256::MAX.is_positive());
assert!(!I256::MAX.is_negative());
assert!(!I256::MAX.is_zero());
assert_eq!(I256::one().signum(), I256::one());
assert!(I256::one().is_positive());
assert!(!I256::one().is_negative());
assert!(!I256::one().is_zero());
assert_eq!(I256::MIN.signum(), I256::minus_one());
assert!(!I256::MIN.is_positive());
assert!(I256::MIN.is_negative());
assert!(!I256::MIN.is_zero());
assert_eq!(I256::minus_one().signum(), I256::minus_one());
assert!(!I256::minus_one().is_positive());
assert!(I256::minus_one().is_negative());
assert!(!I256::minus_one().is_zero());
assert_eq!(I256::zero().signum(), I256::zero());
assert!(!I256::zero().is_positive());
assert!(!I256::zero().is_negative());
assert!(I256::zero().is_zero());
assert_eq!(
I256::from_dec_str("314159265358979323846264338327950288419716")
.unwrap()
.signum(),
I256::one(),
);
assert_eq!(
I256::from_dec_str("-314159265358979323846264338327950288419716")
.unwrap()
.signum(),
I256::minus_one(),
);
}
#[test]
fn abs() {
let positive = I256::from_dec_str("314159265358979323846264338327950288419716")
.unwrap()
.signum();
let negative = -positive;
assert_eq!(positive.abs(), positive);
assert_eq!(negative.abs(), positive);
assert_eq!(I256::zero().abs(), I256::zero());
assert_eq!(I256::MAX.abs(), I256::MAX);
assert_eq!((-I256::MAX).abs(), I256::MAX);
assert_eq!(I256::MIN.checked_abs(), None);
}
#[test]
fn neg() {
let positive = I256::from_dec_str("314159265358979323846264338327950288419716")
.unwrap()
.signum();
let negative = -positive;
assert_eq!(-positive, negative);
assert_eq!(-negative, positive);
assert_eq!(-I256::zero(), I256::zero());
assert_eq!(-(-I256::MAX), I256::MAX);
assert_eq!(I256::MIN.checked_neg(), None);
}
#[test]
fn bits() {
assert_eq!(I256::from(0b1000).bits(), 5);
assert_eq!(I256::from(-0b1000).bits(), 4);
assert_eq!(I256::from(i64::MAX).bits(), 64);
assert_eq!(I256::from(i64::MIN).bits(), 64);
assert_eq!(I256::MAX.bits(), 256);
assert_eq!(I256::MIN.bits(), 256);
assert_eq!(I256::zero().bits(), 0);
}
#[test]
fn bit_shift() {
assert_eq!(I256::one() << 255, I256::MIN);
assert_eq!(I256::MIN >> 255, I256::one());
}
#[test]
fn addition() {
assert_eq!(I256::MIN.overflowing_add(I256::MIN), (I256::zero(), true));
assert_eq!(I256::MAX.overflowing_add(I256::MAX), (I256::from(-2), true));
assert_eq!(
I256::MIN.overflowing_add(I256::minus_one()),
(I256::MAX, true)
);
assert_eq!(I256::MAX.overflowing_add(I256::one()), (I256::MIN, true));
assert_eq!(I256::MAX + I256::MIN, I256::minus_one());
assert_eq!(I256::from(2) + I256::from(40), I256::from(42));
assert_eq!(I256::zero() + I256::zero(), I256::zero());
assert_eq!(I256::MAX.saturating_add(I256::MAX), I256::MAX);
assert_eq!(I256::MIN.saturating_add(I256::minus_one()), I256::MIN);
}
#[test]
#[allow(clippy::eq_op)]
fn subtraction() {
assert_eq!(I256::MIN.overflowing_sub(I256::MAX), (I256::one(), true));
assert_eq!(
I256::MAX.overflowing_sub(I256::MIN),
(I256::minus_one(), true)
);
assert_eq!(I256::MIN.overflowing_sub(I256::one()), (I256::MAX, true));
assert_eq!(
I256::MAX.overflowing_sub(I256::minus_one()),
(I256::MIN, true)
);
assert_eq!(I256::zero().overflowing_sub(I256::MIN), (I256::MIN, true));
assert_eq!(I256::MAX - I256::MAX, I256::zero());
assert_eq!(I256::from(2) - I256::from(44), I256::from(-42));
assert_eq!(I256::zero() - I256::zero(), I256::zero());
assert_eq!(I256::MAX.saturating_sub(I256::MIN), I256::MAX);
assert_eq!(I256::MIN.saturating_sub(I256::one()), I256::MIN);
}
#[test]
fn multiplication() {
assert_eq!(I256::MIN.overflowing_mul(I256::MAX), (I256::MIN, true));
assert_eq!(I256::MAX.overflowing_mul(I256::MIN), (I256::MIN, true));
assert_eq!(I256::MIN * I256::one(), I256::MIN);
assert_eq!(I256::from(2) * I256::from(-21), I256::from(-42));
assert_eq!(I256::MAX.saturating_mul(I256::MAX), I256::MAX);
assert_eq!(I256::MAX.saturating_mul(I256::from(2)), I256::MAX);
assert_eq!(I256::MIN.saturating_mul(I256::from(-2)), I256::MAX);
assert_eq!(I256::MIN.saturating_mul(I256::MAX), I256::MIN);
assert_eq!(I256::MIN.saturating_mul(I256::from(2)), I256::MIN);
assert_eq!(I256::MAX.saturating_mul(I256::from(-2)), I256::MIN);
assert_eq!(I256::zero() * I256::zero(), I256::zero());
assert_eq!(I256::one() * I256::zero(), I256::zero());
assert_eq!(I256::MAX * I256::zero(), I256::zero());
assert_eq!(I256::MIN * I256::zero(), I256::zero());
}
#[test]
fn division() {
assert_eq!(I256::MIN.overflowing_div(I256::from(-1)), (I256::MIN, true));
assert_eq!(I256::MIN / I256::MAX, I256::from(-1));
assert_eq!(I256::MAX / I256::MIN, I256::zero());
assert_eq!(I256::MIN / I256::one(), I256::MIN);
assert_eq!(I256::from(-42) / I256::from(-21), I256::from(2));
assert_eq!(I256::from(-42) / I256::from(2), I256::from(-21));
assert_eq!(I256::from(42) / I256::from(-21), I256::from(-2));
assert_eq!(I256::from(42) / I256::from(21), I256::from(2));
assert_eq!(I256::MIN.saturating_div(I256::from(-1)), I256::MAX);
}
#[test]
#[should_panic]
fn division_by_zero() {
let _ = I256::one() / I256::zero();
}
#[test]
fn div_euclid() {
let a = I256::from(7);
let b = I256::from(4);
assert_eq!(a.div_euclid(b), I256::one()); assert_eq!(a.div_euclid(-b), -I256::one()); assert_eq!((-a).div_euclid(b), -I256::from(2)); assert_eq!((-a).div_euclid(-b), I256::from(2));
assert_eq!(
I256::MIN.overflowing_div_euclid(-I256::one()),
(I256::MIN, true)
);
assert_eq!(I256::MIN.wrapping_div_euclid(-I256::one()), I256::MIN);
assert_eq!(I256::MIN.checked_div_euclid(-I256::one()), None);
assert_eq!(I256::one().checked_div_euclid(I256::zero()), None);
}
#[test]
fn rem_euclid() {
let a = I256::from(7); let b = I256::from(4);
assert_eq!(a.rem_euclid(b), I256::from(3));
assert_eq!((-a).rem_euclid(b), I256::one());
assert_eq!(a.rem_euclid(-b), I256::from(3));
assert_eq!((-a).rem_euclid(-b), I256::one());
assert_eq!(a.overflowing_rem_euclid(b), (I256::from(3), false));
assert_eq!(
I256::min_value().overflowing_rem_euclid(-I256::one()),
(I256::zero(), true)
);
assert_eq!(
I256::from(100).wrapping_rem_euclid(I256::from(10)),
I256::zero()
);
assert_eq!(
I256::min_value().wrapping_rem_euclid(-I256::one()),
I256::zero()
);
assert_eq!(a.checked_rem_euclid(b), Some(I256::from(3)));
assert_eq!(a.checked_rem_euclid(I256::zero()), None);
assert_eq!(I256::min_value().checked_rem_euclid(-I256::one()), None);
}
#[test]
#[should_panic]
fn div_euclid_by_zero() {
let _ = I256::one().div_euclid(I256::zero());
assert_eq!(I256::MIN.div_euclid(-I256::one()), I256::MAX);
}
#[test]
#[cfg_attr(debug_assertions, should_panic)]
fn div_euclid_overflow() {
let _ = I256::MIN.div_euclid(-I256::one());
}
#[test]
#[should_panic]
fn mod_by_zero() {
let _ = I256::one() % I256::zero();
}
#[test]
fn remainder() {
assert_eq!(
I256::MIN.overflowing_rem(I256::from(-1)),
(I256::zero(), true)
);
assert_eq!(I256::from(-5) % I256::from(-2), I256::from(-1));
assert_eq!(I256::from(5) % I256::from(-2), I256::one());
assert_eq!(I256::from(-5) % I256::from(2), I256::from(-1));
assert_eq!(I256::from(5) % I256::from(2), I256::one());
assert_eq!(I256::MIN.checked_rem(I256::from(-1)), None);
assert_eq!(I256::one().checked_rem(I256::one()), Some(I256::zero()));
}
#[test]
fn exponentiation() {
assert_eq!(I256::from(1000).saturating_pow(1000), I256::MAX);
assert_eq!(I256::from(-1000).saturating_pow(1001), I256::MIN);
assert_eq!(I256::from(2).pow(64), I256::from(1u128 << 64));
assert_eq!(I256::from(-2).pow(63), I256::from(i64::MIN));
assert_eq!(I256::zero().pow(42), I256::zero());
assert_eq!(I256::exp10(18).to_string(), "1000000000000000000");
}
#[test]
fn iterators() {
assert_eq!((1..=5).map(I256::from).sum::<I256>(), I256::from(15));
assert_eq!((1..=5).map(I256::from).product::<I256>(), I256::from(120));
}
#[test]
fn json() {
assert_eq!(json!(I256::from(42)), json!("0x2a"));
assert_eq!(json!(I256::minus_one()), json!(U256::MAX));
}
}