use core::{
convert::TryFrom,
iter,
ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Rem, RemAssign, Sub, SubAssign},
str::FromStr,
};
#[cfg(feature = "serde")]
use serde::{
de::{Error as _, Unexpected},
Deserialize, Deserializer, Serialize,
};
use crate::{
error::{ParseIntError, ParseIntErrorKind, TryFromIntError},
MAX_SAFE_INT,
};
pub const MAX_SAFE_UINT: u64 = 0x001F_FFFF_FFFF_FFFF;
#[derive(Clone, Copy, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
#[cfg_attr(feature = "serde", derive(Serialize))]
pub struct UInt(u64);
impl UInt {
pub const MIN: Self = Self(0);
pub const MAX: Self = Self(MAX_SAFE_UINT);
#[must_use]
pub fn new(val: u64) -> Option<Self> {
if val <= MAX_SAFE_UINT {
Some(Self(val))
} else {
None
}
}
#[must_use]
pub fn new_wrapping(val: u64) -> Self {
Self(val & MAX_SAFE_UINT)
}
#[must_use]
pub fn new_saturating(val: u64) -> Self {
if val <= MAX_SAFE_UINT {
Self(val)
} else {
Self::MAX
}
}
#[must_use]
fn new_(val: u64) -> Self {
if cfg!(debug_assertions) {
assert!(val <= MAX_SAFE_UINT);
Self(val)
} else {
Self::new_wrapping(val)
}
}
fn assign_(&mut self, val: u64) {
if cfg!(debug_assertions) {
assert!(val <= MAX_SAFE_UINT);
*self = Self(val);
} else {
*self = Self::new_wrapping(val);
}
}
#[must_use]
#[deprecated = "Use `UInt::MIN` instead."]
pub const fn min_value() -> Self {
Self(0)
}
#[must_use]
#[deprecated = "Use `UInt::MAX` instead."]
pub const fn max_value() -> Self {
Self(MAX_SAFE_UINT)
}
#[must_use]
pub fn is_power_of_two(self) -> bool {
self.0.is_power_of_two()
}
#[must_use]
pub fn checked_next_power_of_two(self) -> Option<Self> {
self.0.checked_next_power_of_two().and_then(Self::new)
}
pub fn from_str_radix(src: &str, radix: u32) -> Result<Self, ParseIntError> {
let val = u64::from_str_radix(src, radix)?;
if val > MAX_SAFE_UINT {
Err(ParseIntError { kind: ParseIntErrorKind::Overflow })
} else {
Ok(Self(val))
}
}
#[must_use]
pub fn checked_add(self, rhs: Self) -> Option<Self> {
self.0.checked_add(rhs.0).and_then(Self::new)
}
#[must_use]
pub fn checked_sub(self, rhs: Self) -> Option<Self> {
self.0.checked_sub(rhs.0).and_then(Self::new)
}
#[must_use]
pub fn checked_mul(self, rhs: Self) -> Option<Self> {
self.0.checked_mul(rhs.0).and_then(Self::new)
}
#[must_use]
pub fn checked_div(self, rhs: Self) -> Option<Self> {
self.0.checked_div(rhs.0).map(Self)
}
#[must_use]
pub fn checked_rem(self, rhs: Self) -> Option<Self> {
self.0.checked_rem(rhs.0).map(Self)
}
#[must_use]
pub fn checked_neg(self) -> Option<Self> {
self.0.checked_neg().map(Self)
}
#[must_use]
pub fn checked_pow(self, exp: u32) -> Option<Self> {
self.0.checked_pow(exp).and_then(Self::new)
}
#[must_use]
pub fn saturating_add(self, rhs: Self) -> Self {
self.checked_add(rhs).unwrap_or(Self::MAX)
}
#[must_use]
pub fn saturating_sub(self, rhs: Self) -> Self {
self.checked_sub(rhs).unwrap_or(Self::MIN)
}
#[must_use]
pub fn saturating_mul(self, rhs: Self) -> Self {
self.checked_mul(rhs).unwrap_or(Self::MAX)
}
#[must_use]
pub fn saturating_pow(self, exp: u32) -> Self {
Self::new_saturating(self.0.saturating_pow(exp))
}
}
fmt_impls!(UInt);
convert_impls!(UInt, u8, u16, u32, u64, u128, usize, i8, i16, i32, isize);
impl TryFrom<i8> for UInt {
type Error = TryFromIntError;
fn try_from(val: i8) -> Result<Self, TryFromIntError> {
if val >= 0 {
Ok(Self(val as u64))
} else {
Err(TryFromIntError::new())
}
}
}
impl TryFrom<i16> for UInt {
type Error = TryFromIntError;
fn try_from(val: i16) -> Result<Self, TryFromIntError> {
if val >= 0 {
Ok(Self(val as u64))
} else {
Err(TryFromIntError::new())
}
}
}
impl TryFrom<i32> for UInt {
type Error = TryFromIntError;
fn try_from(val: i32) -> Result<Self, TryFromIntError> {
if val >= 0 {
Ok(Self(val as u64))
} else {
Err(TryFromIntError::new())
}
}
}
impl TryFrom<i64> for UInt {
type Error = TryFromIntError;
fn try_from(val: i64) -> Result<Self, TryFromIntError> {
if (0..=MAX_SAFE_INT).contains(&val) {
Ok(Self(val as u64))
} else {
Err(TryFromIntError::new())
}
}
}
impl TryFrom<i128> for UInt {
type Error = TryFromIntError;
fn try_from(val: i128) -> Result<Self, TryFromIntError> {
if (0..=MAX_SAFE_INT.into()).contains(&val) {
Ok(Self(val as u64))
} else {
Err(TryFromIntError::new())
}
}
}
impl From<UInt> for i64 {
fn from(val: UInt) -> Self {
val.0 as i64
}
}
impl From<UInt> for i128 {
fn from(val: UInt) -> Self {
val.0 as i128
}
}
macro_rules! uint_op_impl {
($trait:ident, $method:ident, $assign_trait:ident, $assign_method:ident) => {
impl $trait for UInt {
type Output = Self;
fn $method(self, rhs: Self) -> Self {
Self::new_(<u64 as $trait>::$method(self.0, rhs.0))
}
}
impl $assign_trait for UInt {
fn $assign_method(&mut self, other: Self) {
self.assign_(<u64 as $trait>::$method(self.0, other.0));
}
}
};
}
uint_op_impl!(Add, add, AddAssign, add_assign);
uint_op_impl!(Sub, sub, SubAssign, sub_assign);
uint_op_impl!(Mul, mul, MulAssign, mul_assign);
uint_op_impl!(Div, div, DivAssign, div_assign);
uint_op_impl!(Rem, rem, RemAssign, rem_assign);
impl iter::Sum for UInt {
fn sum<I>(iter: I) -> Self
where
I: Iterator<Item = UInt>,
{
Self::new_(iter.map(|x| x.0).sum())
}
}
impl<'a> iter::Sum<&'a UInt> for UInt {
fn sum<I>(iter: I) -> Self
where
I: Iterator<Item = &'a UInt>,
{
Self::new_(iter.map(|x| x.0).sum())
}
}
impl iter::Product for UInt {
fn product<I>(iter: I) -> Self
where
I: Iterator<Item = UInt>,
{
Self::new_(iter.map(|x| x.0).product())
}
}
impl<'a> iter::Product<&'a UInt> for UInt {
fn product<I>(iter: I) -> Self
where
I: Iterator<Item = &'a UInt>,
{
Self::new_(iter.map(|x| x.0).product())
}
}
impl FromStr for UInt {
type Err = ParseIntError;
fn from_str(src: &str) -> Result<Self, Self::Err> {
let val = u64::from_str(src)?;
if val > MAX_SAFE_UINT {
Err(ParseIntError { kind: ParseIntErrorKind::Overflow })
} else {
Ok(Self(val))
}
}
}
#[cfg(feature = "serde")]
impl<'de> Deserialize<'de> for UInt {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
#[cfg(not(feature = "float_deserialize"))]
{
let val = u64::deserialize(deserializer)?;
Self::new(val).ok_or_else(|| {
D::Error::invalid_value(
Unexpected::Unsigned(val),
&"an integer between 0 and 2^53 - 1",
)
})
}
#[cfg(feature = "float_deserialize")]
{
#[cfg(not(feature = "lax_deserialize"))]
const EXPECTING: &str = "a number between 0 and 2^53 - 1 without fractional component";
#[cfg(feature = "lax_deserialize")]
const EXPECTING: &str = "a number between 0 and 2^53 - 1";
let val = f64::deserialize(deserializer)?;
if val < 0.0 || val > MAX_SAFE_UINT as f64 || !super::is_acceptable_float(val) {
Err(D::Error::invalid_value(Unexpected::Float(val), &EXPECTING))
} else {
Ok(Self(val as u64))
}
}
}
}
#[cfg(test)]
mod tests {
use super::{UInt, MAX_SAFE_UINT};
#[test]
fn uint_ops() {
assert_eq!(uint!(5) + uint!(3), uint!(8));
assert_eq!(uint!(2) - uint!(1), uint!(1));
assert_eq!(uint!(4) * uint!(2), uint!(8));
assert_eq!(uint!(5) / uint!(2), uint!(2));
assert_eq!(uint!(11) % uint!(4), uint!(3));
}
#[test]
fn uint_assign_ops() {
let mut uint = uint!(1);
uint += uint!(3);
assert_eq!(uint, uint!(4));
uint -= uint!(1);
assert_eq!(uint, uint!(3));
uint *= uint!(3);
assert_eq!(uint, uint!(9));
uint /= uint!(3);
assert_eq!(uint, uint!(3));
uint %= uint!(2);
assert_eq!(uint, uint!(1));
}
#[test]
fn uint_wrapping_new() {
assert_eq!(UInt::new_wrapping(MAX_SAFE_UINT + 1), uint!(0));
}
#[test]
#[cfg_attr(debug_assertions, ignore)]
fn uint_underflow_wrap() {
assert_eq!(uint!(0) - uint!(1), UInt::MAX);
}
#[test]
#[cfg_attr(debug_assertions, ignore)]
fn uint_overflow_wrap() {
assert_eq!(UInt::MAX + uint!(1), uint!(0));
assert_eq!(UInt::MAX + uint!(5), uint!(4));
}
#[test]
#[should_panic]
#[cfg_attr(not(debug_assertions), ignore)]
fn uint_underflow_panic() {
let _ = uint!(0) - uint!(1);
}
#[test]
#[should_panic]
#[cfg_attr(not(debug_assertions), ignore)]
fn uint_overflow_panic() {
let _ = UInt::MAX + uint!(1);
}
#[test]
fn try_from_uint_for_i_n() {
use core::convert::TryFrom;
let i8_max = i8::MAX as u64;
let i16_max = i16::MAX as u64;
let i32_max = i32::MAX as u64;
assert_eq!(i8::try_from(UInt(0)), Ok(0));
assert_eq!(i8::try_from(UInt(10)), Ok(10));
assert_eq!(i8::try_from(UInt(i8_max)), Ok(i8::MAX));
assert!(i8::try_from(UInt(i8_max + 1)).is_err());
assert_eq!(i16::try_from(UInt(0)), Ok(0));
assert_eq!(i16::try_from(UInt(10)), Ok(10));
assert_eq!(i16::try_from(UInt(i8_max + 1)), Ok((i8::MAX as i16) + 1));
assert_eq!(i16::try_from(UInt(i16_max)), Ok(i16::MAX));
assert!(i16::try_from(UInt(i16_max + 1)).is_err());
assert_eq!(i32::try_from(UInt(0)), Ok(0));
assert_eq!(i32::try_from(UInt(10)), Ok(10));
assert_eq!(i32::try_from(UInt(i16_max + 1)), Ok((i16::MAX as i32) + 1));
assert_eq!(i32::try_from(UInt(i32_max)), Ok(i32::MAX));
assert!(i32::try_from(UInt(i32_max + 1)).is_err());
}
}