use crate::{
encode_packed::EncodePacked,
primitive::{Primitive, Word},
};
use ethprim::{I256, U256};
use std::{
error::Error,
fmt::{self, Display, Formatter},
mem,
};
macro_rules! impl_bitint {
($(impl $t:ident <$s:ident $n:literal> ($i:ident) ;)*) => {$(
#[doc = concat!(
"A ", stringify!($n), "-bit Solidity ", stringify!($s), " integer."
)]
#[derive(Clone, Copy, Debug, Default, Hash, Eq, Ord, PartialEq, PartialOrd)]
pub struct $t($i);
impl $t {
#[doc = concat!(
"Creates a new ", stringify!($n), "-bit Solidity integer from ",
"its underlying value. Returns `None` if the value does ",
"overflows ", stringify!($n), " bits."
)]
pub const fn new(value: $i) -> Option<Self> {
impl_bitint!(const_new::<$n, $i>(value))
}
#[doc = concat!(
"Creates a new ", stringify!($n), "-bit Solidity integer by ",
"truncating a value to ", stringify!($n), " bits."
)]
pub fn new_truncated(value: $i) -> Self {
Self(Self::truncate(value))
}
#[doc = concat!(
"Creates a new ", stringify!($n), "-bit Solidity integer from ",
"its underlying value without checking whether or not it fits ",
"in ", stringify!($n), " bits."
)]
#[doc = concat!(
"The caller must ensure that the value fits in ",
stringify!($n), " bits."
)]
pub const unsafe fn new_unchecked(value: $i) -> Self {
Self(value)
}
pub const fn get(self) -> $i {
self.0
}
const fn truncate(value: $i) -> $i {
impl_bitint!(const_truncate::<$n, $i>(value))
}
}
impl Primitive for $t {
fn to_word(&self) -> Word {
self.0.to_word()
}
fn from_word(word: Word) -> Option<Self> {
Self::new(<$i>::from_word(word)?)
}
}
impl EncodePacked for $t {
fn packed_size(&self) -> usize {
$n / 8
}
fn encode_packed(&self, out: &mut [u8]) {
const OFFSET: usize = mem::size_of::<$i>() - ($n / 8);
out.copy_from_slice(&self.0.to_be_bytes()[OFFSET..])
}
}
impl TryFrom<$i> for $t {
type Error = TryFromIntegerError;
fn try_from(value: $i) -> Result<Self, Self::Error> {
Self::new(value).ok_or(TryFromIntegerError)
}
}
)*};
(const_new::<$n:literal, I256>($v:expr)) => {
impl_bitint!(const_new256::<$n, I256>($v))
};
(const_new::<$n:literal, U256>($v:expr)) => {
impl_bitint!(const_new256::<$n, U256>($v))
};
(const_new256::<$n:literal, $i:ident>($v:expr)) => {{
let value = $v;
let (hi, _) = value.into_words();
let (hi_truncated, _) = Self::truncate(value).into_words();
if hi == hi_truncated {
Some(Self(value))
} else {
None
}
}};
(const_new::<$n:literal, $i:ident>($v:expr)) => {{
let value = $v;
if value == Self::truncate(value) {
Some(Self(value))
} else {
None
}
}};
(const_truncate::<$n:literal, I256>($v:expr)) => {
impl_bitint!(const_truncate256::<$n, I256>($v))
};
(const_truncate::<$n:literal, U256>($v:expr)) => {
impl_bitint!(const_truncate256::<$n, U256>($v))
};
(const_truncate256::<$n:literal, $i:ident>($v:expr)) => {{
const SHIFT: usize = (mem::size_of::<$i>() * 8) - $n;
let (hi, lo) = $v.into_words();
<$i>::from_words((hi << SHIFT) >> SHIFT, lo)
}};
(const_truncate::<$n:literal, $i:ident>($v:expr)) => {{
const SHIFT: usize = (mem::size_of::<$i>() * 8) - $n;
($v << SHIFT) >> SHIFT
}};
}
pub type Int8 = i8;
pub type Int16 = i16;
pub type Int32 = i32;
pub type Int64 = i64;
pub type Int128 = i128;
pub type Int256 = I256;
pub type Uint8 = u8;
pub type Uint16 = u16;
pub type Uint32 = u32;
pub type Uint64 = u64;
pub type Uint128 = u128;
pub type Uint256 = U256;
impl_bitint! {
impl Int24 <signed 24> (i32);
impl Int40 <signed 40> (i64);
impl Int48 <signed 48> (i64);
impl Int56 <signed 56> (i64);
impl Int72 <signed 72> (i128);
impl Int80 <signed 80> (i128);
impl Int88 <signed 88> (i128);
impl Int96 <signed 96> (i128);
impl Int104 <signed 104> (i128);
impl Int112 <signed 112> (i128);
impl Int120 <signed 120> (i128);
impl Int136 <signed 136> (I256);
impl Int144 <signed 144> (I256);
impl Int152 <signed 152> (I256);
impl Int160 <signed 160> (I256);
impl Int168 <signed 168> (I256);
impl Int176 <signed 176> (I256);
impl Int184 <signed 184> (I256);
impl Int192 <signed 192> (I256);
impl Int200 <signed 200> (I256);
impl Int208 <signed 208> (I256);
impl Int216 <signed 216> (I256);
impl Int224 <signed 224> (I256);
impl Int232 <signed 232> (I256);
impl Int240 <signed 240> (I256);
impl Int248 <signed 248> (I256);
impl Uint24 <unsigned 24> (u32);
impl Uint40 <unsigned 40> (u64);
impl Uint48 <unsigned 48> (u64);
impl Uint56 <unsigned 56> (u64);
impl Uint72 <unsigned 72> (u128);
impl Uint80 <unsigned 80> (u128);
impl Uint88 <unsigned 88> (u128);
impl Uint96 <unsigned 96> (u128);
impl Uint104 <unsigned 104> (u128);
impl Uint112 <unsigned 112> (u128);
impl Uint120 <unsigned 120> (u128);
impl Uint136 <unsigned 136> (U256);
impl Uint144 <unsigned 144> (U256);
impl Uint152 <unsigned 152> (U256);
impl Uint160 <unsigned 160> (U256);
impl Uint168 <unsigned 168> (U256);
impl Uint176 <unsigned 176> (U256);
impl Uint184 <unsigned 184> (U256);
impl Uint192 <unsigned 192> (U256);
impl Uint200 <unsigned 200> (U256);
impl Uint208 <unsigned 208> (U256);
impl Uint216 <unsigned 216> (U256);
impl Uint224 <unsigned 224> (U256);
impl Uint232 <unsigned 232> (U256);
impl Uint240 <unsigned 240> (U256);
impl Uint248 <unsigned 248> (U256);
}
#[derive(Debug)]
pub struct TryFromIntegerError;
impl Display for TryFromIntegerError {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.write_str("value overflows integer")
}
}
impl Error for TryFromIntegerError {}