use crate::U256;
use core::{
cmp::Ordering,
fmt,
hash::{Hash, Hasher},
mem::transmute,
num::NonZero,
};
#[cfg(feature = "codec")]
use scale_info::{
TypeInfo,
prelude::vec::Vec,
scale::{Decode, Encode, EncodeLike, Error, Input, Output},
};
#[derive(Clone, Copy)]
#[cfg_attr(feature = "codec", derive(TypeInfo))]
#[repr(transparent)]
pub struct NonZeroU256(U256);
macro_rules! impl_nonzero_fmt {
($Trait:ident) => {
impl fmt::$Trait for NonZeroU256 {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.get().fmt(f)
}
}
};
}
impl_nonzero_fmt!(Debug);
impl_nonzero_fmt!(Display);
impl_nonzero_fmt!(LowerHex);
impl_nonzero_fmt!(UpperHex);
impl PartialEq for NonZeroU256 {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.get() == other.get()
}
}
impl Eq for NonZeroU256 {}
impl PartialOrd for NonZeroU256 {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
#[inline]
fn lt(&self, other: &Self) -> bool {
self.get() < other.get()
}
#[inline]
fn le(&self, other: &Self) -> bool {
self.get() <= other.get()
}
#[inline]
fn gt(&self, other: &Self) -> bool {
self.get() > other.get()
}
#[inline]
fn ge(&self, other: &Self) -> bool {
self.get() >= other.get()
}
}
impl Ord for NonZeroU256 {
#[inline]
fn cmp(&self, other: &Self) -> Ordering {
self.get().cmp(&other.get())
}
#[inline]
fn max(self, other: Self) -> Self {
Self(self.get().max(other.get()))
}
#[inline]
fn min(self, other: Self) -> Self {
Self(self.get().min(other.get()))
}
#[inline]
fn clamp(self, min: Self, max: Self) -> Self {
Self(self.get().clamp(min.get(), max.get()))
}
}
impl Hash for NonZeroU256 {
#[inline]
fn hash<H>(&self, state: &mut H)
where
H: Hasher,
{
self.get().hash(state)
}
}
impl AsRef<[u64]> for NonZeroU256 {
#[inline]
fn as_ref(&self) -> &[u64] {
self.0.as_ref()
}
}
impl<'a> From<&'a NonZeroU256> for NonZeroU256 {
fn from(x: &'a NonZeroU256) -> NonZeroU256 {
*x
}
}
impl NonZeroU256 {
pub const MIN: NonZeroU256 = unsafe { NonZeroU256::new_unchecked(U256::one()) };
pub const MAX: NonZeroU256 = unsafe { NonZeroU256::new_unchecked(U256::MAX) };
#[must_use]
#[inline]
pub const fn new(n: U256) -> Option<Self> {
if n.is_zero() { None } else { Some(Self(n)) }
}
#[must_use]
#[inline]
pub const unsafe fn new_unchecked(n: U256) -> Self {
unsafe { transmute(n) }
}
#[inline]
pub const fn get(self) -> U256 {
match Self::new(self.0) {
Some(Self(n)) => n,
None => {
unreachable!()
}
}
}
#[inline]
pub fn checked_add(self, other: U256) -> Option<Self> {
self.get()
.checked_add(other)
.map(|result| unsafe { Self::new_unchecked(result) })
}
#[inline]
pub fn saturating_add(self, other: U256) -> Self {
unsafe { Self::new_unchecked(self.get().saturating_add(other)) }
}
#[inline(always)]
pub fn overflowing_add(self, other: U256) -> (Self, bool) {
let result = self.get().overflowing_add(other);
if result.0.is_zero() {
(Self::MIN, true)
} else {
unsafe { (Self::new_unchecked(result.0), result.1) }
}
}
pub fn checked_sub(self, other: U256) -> Option<Self> {
match self.get().overflowing_sub(other) {
(_, true) => None,
(val, _) => Self::new(val),
}
}
pub fn saturating_sub(self, other: U256) -> Self {
match self.get().overflowing_sub(other) {
(_, true) => Self::MIN,
(val, false) => Self::new(val).unwrap_or(Self::MIN),
}
}
#[inline(always)]
pub fn overflowing_sub(self, other: U256) -> (Self, bool) {
let result = self.get().overflowing_sub(other);
if result.0.is_zero() {
(Self::MAX, true)
} else {
unsafe { (Self::new_unchecked(result.0), result.1) }
}
}
#[inline]
pub fn checked_mul(self, other: Self) -> Option<Self> {
self.get()
.checked_mul(other.get())
.map(|result| unsafe { Self::new_unchecked(result) })
}
#[inline]
pub fn saturating_mul(self, other: Self) -> Self {
unsafe { Self::new_unchecked(self.get().saturating_mul(other.get())) }
}
#[inline(always)]
pub fn overflowing_mul(self, other: Self) -> (Self, bool) {
let result = self.get().overflowing_mul(other.get());
if result.0.is_zero() {
(Self::MAX, true)
} else {
unsafe { (Self::new_unchecked(result.0), result.1) }
}
}
#[inline]
pub fn checked_pow(self, other: U256) -> Option<Self> {
self.get()
.checked_pow(other)
.map(|result| unsafe { Self::new_unchecked(result) })
}
#[inline]
pub fn overflowing_pow(self, other: U256) -> (Self, bool) {
let result = self.get().overflowing_pow(other);
if result.0.is_zero() {
(Self::MAX, true)
} else {
unsafe { (Self::new_unchecked(result.0), result.1) }
}
}
#[inline]
pub fn pow(self, other: U256) -> Self {
unsafe { Self::new_unchecked(self.get().pow(other)) }
}
}
impl From<NonZeroU256> for U256 {
#[inline]
fn from(nonzero: NonZeroU256) -> Self {
nonzero.get()
}
}
macro_rules! impl_map_from {
($from:ty) => {
impl From<$from> for NonZeroU256 {
fn from(value: $from) -> Self {
unsafe { Self::new_unchecked(U256::from(value.get())) }
}
}
};
}
impl_map_from!(NonZero<u8>);
impl_map_from!(NonZero<u16>);
impl_map_from!(NonZero<u32>);
impl_map_from!(NonZero<u64>);
impl_map_from!(NonZero<u128>);
macro_rules! impl_try_from {
($from:ty) => {
impl TryFrom<$from> for NonZeroU256 {
type Error = &'static str;
#[inline]
fn try_from(value: $from) -> Result<NonZeroU256, &'static str> {
NonZeroU256::new(U256::from(value)).ok_or("integer value is zero")
}
}
};
}
impl_try_from!(u8);
impl_try_from!(u16);
impl_try_from!(u32);
impl_try_from!(u64);
impl_try_from!(u128);
#[doc(hidden)]
macro_rules! panic_on_overflow {
($name: expr) => {
if $name {
panic!("arithmetic operation overflow")
}
};
}
impl<T> core::ops::Add<T> for NonZeroU256
where
T: Into<U256>,
{
type Output = NonZeroU256;
fn add(self, other: T) -> NonZeroU256 {
let (result, overflow) = self.overflowing_add(other.into());
panic_on_overflow!(overflow);
result
}
}
impl<T> core::ops::Add<T> for &NonZeroU256
where
T: Into<U256>,
{
type Output = NonZeroU256;
fn add(self, other: T) -> NonZeroU256 {
*self + other
}
}
impl<T> core::ops::AddAssign<T> for NonZeroU256
where
T: Into<U256>,
{
fn add_assign(&mut self, other: T) {
let (result, overflow) = self.overflowing_add(other.into());
panic_on_overflow!(overflow);
*self = result
}
}
impl<T> core::ops::Sub<T> for NonZeroU256
where
T: Into<U256>,
{
type Output = NonZeroU256;
#[inline]
fn sub(self, other: T) -> NonZeroU256 {
let (result, overflow) = self.overflowing_sub(other.into());
panic_on_overflow!(overflow);
result
}
}
impl<T> core::ops::Sub<T> for &NonZeroU256
where
T: Into<U256>,
{
type Output = NonZeroU256;
fn sub(self, other: T) -> NonZeroU256 {
*self - other
}
}
impl<T> core::ops::SubAssign<T> for NonZeroU256
where
T: Into<U256>,
{
fn sub_assign(&mut self, other: T) {
let (result, overflow) = self.overflowing_sub(other.into());
panic_on_overflow!(overflow);
*self = result
}
}
impl core::ops::Mul<NonZeroU256> for NonZeroU256 {
type Output = NonZeroU256;
fn mul(self, other: NonZeroU256) -> NonZeroU256 {
let (result, overflow) = self.overflowing_mul(other);
panic_on_overflow!(overflow);
result
}
}
impl<'a> core::ops::Mul<&'a NonZeroU256> for NonZeroU256 {
type Output = NonZeroU256;
fn mul(self, other: &'a NonZeroU256) -> NonZeroU256 {
let (result, overflow) = self.overflowing_mul(*other);
panic_on_overflow!(overflow);
result
}
}
impl<'a> core::ops::Mul<&'a NonZeroU256> for &'a NonZeroU256 {
type Output = NonZeroU256;
fn mul(self, other: &'a NonZeroU256) -> NonZeroU256 {
let (result, overflow) = self.overflowing_mul(*other);
panic_on_overflow!(overflow);
result
}
}
impl core::ops::Mul<NonZeroU256> for &NonZeroU256 {
type Output = NonZeroU256;
fn mul(self, other: NonZeroU256) -> NonZeroU256 {
let (result, overflow) = self.overflowing_mul(other);
panic_on_overflow!(overflow);
result
}
}
impl core::ops::MulAssign<NonZeroU256> for NonZeroU256 {
fn mul_assign(&mut self, other: NonZeroU256) {
let result = *self * other;
*self = result
}
}
#[cfg(feature = "codec")]
macro_rules! impl_for_non_zero {
( $( $name:ty ),* $(,)? ) => {
$(
impl Encode for $name {
fn size_hint(&self) -> usize {
self.get().size_hint()
}
fn encode_to<W: Output + ?Sized>(&self, dest: &mut W) {
self.get().encode_to(dest)
}
fn encode(&self) -> Vec<u8> {
self.get().encode()
}
fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
self.get().using_encoded(f)
}
}
impl EncodeLike for $name {}
impl Decode for $name {
fn decode<I: Input>(input: &mut I) -> Result<Self, Error> {
Self::new(Decode::decode(input)?)
.ok_or_else(|| Error::from("cannot create non-zero number from 0"))
}
}
)*
}
}
#[cfg(feature = "codec")]
impl_for_non_zero!(NonZeroU256);
#[cfg(test)]
mod tests {
extern crate alloc;
use super::*;
use alloc::format;
#[test]
fn nonzero_u256_from_to_u256() {
let u256 = U256::from(42u64);
let nz = NonZeroU256::new(u256).unwrap();
assert_eq!(u256, nz.into());
assert_eq!(format!("{u256}"), format!("{nz}"));
assert_eq!(format!("{u256:?}"), format!("{nz:?}"));
}
#[test]
fn nonzero_u256_from_nz64() {
let nzu64 = NonZero::<u64>::new(42u64).unwrap();
let nz: NonZeroU256 = nzu64.into();
assert_eq!(U256::from(nzu64.get()), nz.get());
}
#[test]
fn nonzero_u256_from_zero() {
let zero = 0u64;
let opt = NonZeroU256::new(U256::from(zero));
assert_eq!(None, opt);
let res = TryInto::<NonZeroU256>::try_into(zero);
assert_eq!(Err("integer value is zero"), res);
}
#[test]
fn nonzero_u256_overflowing_add() {
let nzu256 = NonZeroU256::MAX;
let result = nzu256.overflowing_add(1u64.into());
assert_eq!((NonZeroU256::MIN, true), result);
}
#[test]
fn nonzero_u256_overflowing_sub() {
let nzu256 = NonZeroU256::MIN;
let result = nzu256.overflowing_sub(1u64.into());
assert_eq!((NonZeroU256::MAX, true), result);
}
#[test]
fn nonzero_u256_overflowing_mul() {
let mut nzu256 = NonZeroU256::from(NonZero::<u128>::MAX);
nzu256 += 1;
let result = nzu256.overflowing_mul(nzu256);
assert_eq!((NonZeroU256::MAX, true), result);
}
#[test]
fn nonzero_u256_overflowing_pow() {
let mut nzu256 = NonZeroU256::from(NonZero::<u128>::MAX);
nzu256 += 1;
let result: (NonZeroU256, bool) = nzu256.overflowing_pow(2.into());
assert_eq!((NonZeroU256::MAX, true), result);
}
}