use core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not};
use crate::{const_for, Uint};
#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct U256(pub Uint<4>);
macro_rules! to_from_array {
($($to_fn:ident $from_fn:ident $uX:ident $n:expr);*;) => {
$(
pub fn $from_fn(mut x: [$uX; $n]) -> Self {
const_for!(i in {0..x.len()} {
x[i] = $uX::from_le(x[i]);
});
let mut res = Self(Uint(bytemuck::try_cast(x).unwrap()));
const_for!(i in {0..res.0.0.len()} {
res.0.0[i] = u64::from_le(res.0.0[i]);
});
res
}
pub fn $to_fn(self) -> [$uX; $n] {
let mut tmp = self;
const_for!(i in {0..tmp.0.0.len()} {
tmp.0.0[i] = u64::from_le(self.0.0[i]);
});
let mut x: [$uX; $n] = bytemuck::try_cast(tmp.0.0).unwrap();
const_for!(i in {0..x.len()} {
x[i] = $uX::from_le(x[i]);
});
x
}
)*
};
}
macro_rules! to_from_primitive {
($($to_fn:ident $from_fn:ident $uX:ident);*;) => {
$(
pub const fn $from_fn(x: $uX) -> Self {
let mut res = Self::zero();
res.0.0[0] = x as u64;
res
}
pub const fn $to_fn(self) -> $uX {
self.0.0[0] as $uX
}
)*
};
}
macro_rules! try_resize {
($($try_resize_fn:ident $resize_fn:ident $uX:ident $n:expr);*;) => {
$(
pub const fn $try_resize_fn(self) -> Option<$uX> {
if self.sig_bits() > $n {
None
} else {
Some(self.$resize_fn())
}
}
)*
};
}
impl U256 {
to_from_array!(
to_u8_array from_u8_array u8 32;
to_u16_array from_u16_array u16 16;
to_u32_array from_u32_array u32 8;
to_u128_array from_u128_array u128 2;
);
to_from_primitive!(
resize_to_u8 from_u8 u8;
resize_to_u16 from_u16 u16;
resize_to_u32 from_u32 u32;
resize_to_u64 from_u64 u64;
);
try_resize!(
try_resize_to_bool resize_to_bool bool 1;
try_resize_to_u8 resize_to_u8 u8 8;
try_resize_to_u16 resize_to_u16 u16 16;
try_resize_to_u32 resize_to_u32 u32 32;
try_resize_to_u64 resize_to_u64 u64 64;
try_resize_to_u128 resize_to_u128 u128 128;
);
pub const fn from_u64_array(x: [u64; 4]) -> Self {
Self(Uint::from_u64_array(x))
}
pub const fn to_u64_array(self) -> [u64; 4] {
self.0 .0
}
pub const fn from_bool(x: bool) -> Self {
let mut res = Self::zero();
res.0 .0[0] = x as u64;
res
}
pub const fn resize_to_bool(self) -> bool {
(self.0 .0[0] & 1) != 0
}
pub const fn from_u128(x: u128) -> Self {
let mut res = Self::zero();
res.0 .0[0] = x as u64;
res.0 .0[1] = (x >> 64) as u64;
res
}
pub const fn resize_to_u128(self) -> u128 {
(self.0 .0[0] as u128) | ((self.0 .0[1] as u128) << 64)
}
pub const fn zero() -> Self {
Self(Uint::zero())
}
pub const fn one() -> Self {
Self(Uint::one())
}
pub const fn max_value() -> Self {
Self(Uint::max_value())
}
pub const fn is_zero(self) -> bool {
self.0.is_zero()
}
pub const fn sig_bits(self) -> usize {
256usize.wrapping_sub(self.lz())
}
pub fn as_u8_slice_mut(&mut self) -> &mut [u8; 32] {
bytemuck::try_cast_mut(&mut self.0 .0).unwrap()
}
pub fn from_bytes(bytes: &[u8]) -> Option<Self> {
if bytes.len() > 32 {
return None
}
let mut a = [0u8; 32];
a[..bytes.len()].copy_from_slice(bytes);
Some(U256::from_u8_array(a))
}
pub fn from_bytes_be(bytes: &[u8]) -> Option<Self> {
if bytes.len() > 32 {
return None
}
let mut a = [0u8; 32];
a[(32 - bytes.len())..].copy_from_slice(bytes);
a.reverse();
Some(U256::from_u8_array(a))
}
pub fn from_u8_array_be(mut x: [u8; 32]) -> Self {
x.reverse();
Self::from_u8_array(x)
}
pub fn to_u8_array_be(self) -> [u8; 32] {
let mut a = self.to_u8_array();
a.reverse();
a
}
pub const fn overflowing_add(self, other: Self) -> (Self, bool) {
let tmp = self.0.overflowing_add(other.0);
(Self(tmp.0), tmp.1)
}
pub const fn overflowing_sub(self, other: Self) -> (Self, bool) {
let tmp = self.0.overflowing_sub(other.0);
(Self(tmp.0), tmp.1)
}
pub const fn overflowing_mul(self, other: Self) -> (Self, bool) {
let tmp = self.0.overflowing_mul(other.0);
(Self(tmp.0), tmp.1)
}
#[must_use]
pub const fn wrapping_add(self, other: Self) -> Self {
Self(self.0.wrapping_add(other.0))
}
#[must_use]
pub const fn wrapping_sub(self, other: Self) -> Self {
Self(self.0.wrapping_sub(other.0))
}
#[must_use]
pub const fn wrapping_mul(self, other: Self) -> Self {
Self(self.0.wrapping_mul(other.0))
}
#[must_use]
pub const fn wrapping_shl(self, s: usize) -> Self {
Self(self.0.wrapping_shl(s))
}
#[must_use]
pub const fn wrapping_shr(self, s: usize) -> Self {
Self(self.0.wrapping_shr(s))
}
pub const fn checked_add(self, rhs: Self) -> Option<Self> {
match self.0.checked_add(rhs.0) {
Some(x) => Some(Self(x)),
None => None,
}
}
pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
match self.0.checked_sub(rhs.0) {
Some(x) => Some(Self(x)),
None => None,
}
}
pub const fn checked_mul(self, rhs: Self) -> Option<Self> {
match self.0.checked_mul(rhs.0) {
Some(x) => Some(Self(x)),
None => None,
}
}
pub const fn checked_shl(self, s: usize) -> Option<Self> {
match self.0.checked_shl(s) {
Some(x) => Some(Self(x)),
None => None,
}
}
pub const fn checked_shr(self, s: usize) -> Option<Self> {
match self.0.checked_shr(s) {
Some(x) => Some(Self(x)),
None => None,
}
}
#[must_use]
pub const fn shl1(self) -> Option<Self> {
if self.msb() {
return None
}
match self.checked_shl(1) {
Some(x) => Some(x),
None => unreachable!(),
}
}
#[must_use]
pub const fn shr1(self) -> Self {
match self.checked_shr(1) {
Some(x) => x,
None => unreachable!(),
}
}
pub const fn checked_rotl(self, s: usize) -> Option<Self> {
match self.0.checked_rotl(s) {
Some(x) => Some(Self(x)),
None => None,
}
}
#[cfg(feature = "rand_support")]
pub fn rand_using<R>(rng: &mut R) -> Self
where
R: rand_core::RngCore,
{
Self(Uint::rand_using(rng))
}
}
impl U256 {
pub const fn bw() -> usize {
Uint::<4>::bw()
}
pub const fn lsb(&self) -> bool {
self.0.lsb()
}
pub const fn msb(&self) -> bool {
self.0.msb()
}
pub const fn lz(&self) -> usize {
self.0.lz()
}
pub const fn tz(&self) -> usize {
self.0.tz()
}
pub const fn count_ones(&self) -> usize {
self.0.count_ones()
}
pub const fn const_eq(&self, rhs: &Self) -> bool {
self.0.const_eq(&rhs.0)
}
pub const fn const_lt(&self, rhs: &Self) -> bool {
self.0.const_lt(&rhs.0)
}
pub const fn const_le(&self, rhs: &Self) -> bool {
self.0.const_le(&rhs.0)
}
pub const fn const_gt(&self, rhs: &Self) -> bool {
self.0.const_gt(&rhs.0)
}
pub const fn const_ge(&self, rhs: &Self) -> bool {
self.0.const_eq(&rhs.0)
}
pub const fn overflowing_short_cin_mul(self, cin: u64, rhs: u64) -> (Self, u64) {
let tmp = self.0.overflowing_short_cin_mul(cin, rhs);
(Self(tmp.0), tmp.1)
}
pub const fn overflowing_short_mul_add(self, lhs: Self, rhs: u64) -> (Self, bool) {
let tmp = self.0.overflowing_short_mul_add(lhs.0, rhs);
(Self(tmp.0), tmp.1)
}
pub const fn overflowing_mul_add(self, lhs: Self, rhs: Self) -> (Self, bool) {
let tmp = self.0.overflowing_mul_add(lhs.0, rhs.0);
(Self(tmp.0), tmp.1)
}
pub const fn checked_short_divide(self, div: u64) -> Option<(Self, u64)> {
match self.0.checked_short_divide(div) {
Some((x, o)) => Some((Self(x), o)),
None => None,
}
}
pub const fn panicking_short_divide(self, div: u64) -> (Self, u64) {
let tmp = self.0.panicking_short_divide(div);
(Self(tmp.0), tmp.1)
}
pub const fn divide(self, div: Self) -> Option<(Self, Self)> {
match self.0.divide(div.0) {
Some((x, y)) => Some((Self(x), Self(y))),
None => None,
}
}
}
impl Default for U256 {
fn default() -> Self {
Self::zero()
}
}
impl Not for U256 {
type Output = Self;
fn not(self) -> Self::Output {
Self(self.0.const_not())
}
}
impl BitOr for U256 {
type Output = Self;
fn bitor(self, rhs: Self) -> Self::Output {
Self(self.0.const_or(rhs.0))
}
}
impl BitAnd for U256 {
type Output = Self;
fn bitand(self, rhs: Self) -> Self::Output {
Self(self.0.const_and(rhs.0))
}
}
impl BitXor for U256 {
type Output = Self;
fn bitxor(self, rhs: Self) -> Self::Output {
Self(self.0.const_xor(rhs.0))
}
}
impl BitOrAssign for U256 {
fn bitor_assign(&mut self, rhs: Self) {
*self = Self(self.0.const_or(rhs.0));
}
}
impl BitAndAssign for U256 {
fn bitand_assign(&mut self, rhs: Self) {
*self = Self(self.0.const_and(rhs.0));
}
}
impl BitXorAssign for U256 {
fn bitxor_assign(&mut self, rhs: Self) {
*self = Self(self.0.const_xor(rhs.0));
}
}