ex3_node_types/number/
mod.rsuse core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Rem, RemAssign, Sub, SubAssign};
use ic_stable_structures::{storable::Bound, Storable};
use num_bigint::BigUint;
use num_traits::{CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, One, ToPrimitive, Zero};
use serde::{Deserialize, Serialize};
use std::fmt::Display;
#[derive(Debug, Clone, Default, Hash, PartialEq, Eq, PartialOrd, Ord, Deserialize, Serialize)]
#[serde(transparent)]
pub struct Ex3Uint(pub BigUint);
mod add;
mod compare;
mod convert;
mod div;
mod mul;
mod pow;
mod rem;
mod sub;
impl Zero for Ex3Uint {
fn zero() -> Self {
Ex3Uint(BigUint::zero())
}
fn is_zero(&self) -> bool {
self.0.is_zero()
}
}
impl One for Ex3Uint {
fn one() -> Self {
Ex3Uint(BigUint::one())
}
fn set_one(&mut self) {
*self = One::one();
}
fn is_one(&self) -> bool
where
Self: PartialEq,
{
*self == Self::one()
}
}
impl Add for Ex3Uint {
type Output = Ex3Uint;
fn add(self, rhs: Self) -> Self::Output {
Ex3Uint(self.0 + rhs.0)
}
}
impl CheckedAdd for Ex3Uint {
fn checked_add(&self, rhs: &Self) -> Option<Self> {
self.0.checked_add(&rhs.0).map(Self)
}
}
impl AddAssign for Ex3Uint {
fn add_assign(&mut self, rhs: Self) {
self.0 += rhs.0;
}
}
impl Sub for Ex3Uint {
type Output = Ex3Uint;
fn sub(self, rhs: Self) -> Self::Output {
Ex3Uint(self.0 - rhs.0)
}
}
impl CheckedSub for Ex3Uint {
fn checked_sub(&self, rhs: &Self) -> Option<Self> {
self.0.checked_sub(&rhs.0).map(Self)
}
}
impl SubAssign for Ex3Uint {
fn sub_assign(&mut self, rhs: Self) {
self.0 -= rhs.0;
}
}
impl Div for Ex3Uint {
type Output = Ex3Uint;
fn div(self, rhs: Self) -> Self::Output {
Ex3Uint(self.0 / rhs.0)
}
}
impl CheckedDiv for Ex3Uint {
fn checked_div(&self, rhs: &Self) -> Option<Self> {
self.0.checked_div(&rhs.0).map(Self)
}
}
impl DivAssign for Ex3Uint {
fn div_assign(&mut self, rhs: Self) {
self.0 /= rhs.0;
}
}
impl Mul for Ex3Uint {
type Output = Ex3Uint;
fn mul(self, rhs: Self) -> Self::Output {
Ex3Uint(self.0 * rhs.0)
}
}
impl CheckedMul for Ex3Uint {
fn checked_mul(&self, rhs: &Self) -> Option<Self> {
self.0.checked_mul(&rhs.0).map(Self)
}
}
impl MulAssign for Ex3Uint {
fn mul_assign(&mut self, rhs: Self) {
self.0 *= rhs.0;
}
}
impl Rem for Ex3Uint {
type Output = Ex3Uint;
fn rem(self, rhs: Self) -> Self::Output {
Ex3Uint(self.0 % rhs.0)
}
}
impl RemAssign for Ex3Uint {
fn rem_assign(&mut self, rhs: Self) {
self.0 %= rhs.0;
}
}
impl Display for Ex3Uint {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
impl Storable for Ex3Uint {
fn to_bytes(&self) -> std::borrow::Cow<[u8]> {
self.0.to_bytes_le().into()
}
fn from_bytes(bytes: std::borrow::Cow<[u8]>) -> Self {
Self(BigUint::from_bytes_le(&bytes))
}
const BOUND: Bound = Bound::Bounded {
max_size: 32,
is_fixed_size: false,
};
}
impl std::iter::Step for Ex3Uint {
fn steps_between(start: &Self, end: &Self) -> Option<usize> {
end.0.checked_sub(&start.0).map(|x| x.to_usize().unwrap())
}
fn forward_checked(start: Self, count: usize) -> Option<Self> {
start.0.checked_add(&BigUint::from(count)).map(|x| x.into())
}
fn backward_checked(start: Self, count: usize) -> Option<Self> {
start.0.checked_sub(&BigUint::from(count)).map(|x| x.into())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_to_bytes() {
let num = Ex3Uint(BigUint::from(u128::MAX));
let bytes = num.to_bytes();
assert!(bytes.len() <= 32);
let num_decode = Ex3Uint::from_bytes(bytes.into());
assert_eq!(num, num_decode);
}
#[test]
fn test_add() {
let num1 = Ex3Uint(BigUint::from(10u128));
let num2 = Ex3Uint(BigUint::from(20u128));
let sum = num1 + num2;
assert_eq!(sum.0, BigUint::from(30u128));
}
#[test]
fn test_sub() {
let num1 = Ex3Uint(BigUint::from(20u128));
let num2 = Ex3Uint(BigUint::from(10u128));
let diff = num1 - num2;
assert_eq!(diff.0, BigUint::from(10u128));
}
#[test]
fn test_checked_sub() {
let num1 = Ex3Uint(BigUint::from(20u128));
let num2 = Ex3Uint(BigUint::from(10u128));
let diff = num1.checked_sub(&num2).unwrap();
assert_ne!(diff, num1);
assert_eq!(diff.0, BigUint::from(10u128));
}
}