use crate::{Decimal, NumericValue};
use candid::{CandidType, Nat as WrappedNat};
use derive_more::{Add, AddAssign, Sub, SubAssign};
use num_bigint::BigUint;
use serde::{Deserialize, Serialize};
use std::{
fmt,
iter::{Product, Sum},
ops::{Div, DivAssign, Mul, MulAssign},
str::FromStr,
};
#[derive(
Add,
AddAssign,
CandidType,
Clone,
Debug,
Default,
Eq,
PartialEq,
Hash,
Ord,
PartialOrd,
Serialize,
Deserialize,
Sub,
SubAssign,
)]
pub struct NatBig(WrappedNat);
impl NatBig {
#[must_use]
pub const fn from_candid(value: WrappedNat) -> Self {
Self(value)
}
#[must_use]
pub fn from_biguint(value: BigUint) -> Self {
Self::from_candid(WrappedNat::from(value))
}
#[must_use]
pub fn u32_digits(&self) -> Vec<u32> {
self.0.0.to_u32_digits()
}
#[must_use]
pub fn to_u128(&self) -> Option<u128> {
let big = &self.0.0;
u128::try_from(big).ok()
}
#[must_use]
pub fn to_u64(&self) -> Option<u64> {
let big = &self.0.0;
u64::try_from(big).ok()
}
#[must_use]
pub fn to_leb128(&self) -> Vec<u8> {
let mut out = Vec::new();
let encoded = self.0.encode(&mut out);
debug_assert!(
encoded.is_ok(),
"Vec-backed unsigned LEB128 encoding failed"
);
out
}
pub(crate) fn to_magnitude_bytes(&self) -> Vec<u8> {
self.0.0.to_bytes_be()
}
pub(crate) fn from_magnitude_bytes(magnitude: &[u8]) -> Self {
Self::from_biguint(BigUint::from_bytes_be(magnitude))
}
#[must_use]
pub fn saturating_add(self, rhs: Self) -> Self {
Self(self.0 + rhs.0)
}
#[must_use]
pub fn saturating_sub(self, rhs: Self) -> Self {
if rhs > self {
return Self::default();
}
Self(self.0 - rhs.0)
}
}
impl fmt::Display for NatBig {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
impl FromStr for NatBig {
type Err = <WrappedNat as FromStr>::Err;
fn from_str(s: &str) -> Result<Self, Self::Err> {
WrappedNat::from_str(s).map(Self::from_candid)
}
}
impl Div for NatBig {
type Output = Self;
fn div(self, other: Self) -> Self::Output {
Self(self.0 / other.0)
}
}
impl DivAssign for NatBig {
fn div_assign(&mut self, other: Self) {
self.0 /= other.0;
}
}
impl From<u64> for NatBig {
fn from(n: u64) -> Self {
Self::from_candid(WrappedNat::from(n))
}
}
impl From<u32> for NatBig {
fn from(n: u32) -> Self {
Self::from_candid(WrappedNat::from(n))
}
}
impl Mul for NatBig {
type Output = Self;
fn mul(self, other: Self) -> Self::Output {
Self(self.0 * other.0)
}
}
impl MulAssign for NatBig {
fn mul_assign(&mut self, other: Self) {
self.0 *= other.0;
}
}
impl NumericValue for NatBig {
fn try_to_decimal(&self) -> Option<Decimal> {
self.to_u128().and_then(Decimal::from_u128)
}
fn try_from_decimal(value: Decimal) -> Option<Self> {
value.to_u128().map(WrappedNat::from).map(Self::from_candid)
}
}
impl Product for NatBig {
fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
iter.fold(Self::from(1_u32), |acc, value| acc * value)
}
}
impl Sum for NatBig {
fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
iter.fold(Self::default(), |acc, x| acc + x)
}
}
impl TryFrom<i32> for NatBig {
type Error = std::num::TryFromIntError;
fn try_from(n: i32) -> Result<Self, Self::Error> {
let v = Self::from_candid(WrappedNat::from(u32::try_from(n)?));
Ok(v)
}
}