use crate::{Decimal, NumericValue};
use candid::{CandidType, Int as WrappedInt};
use derive_more::{Add, AddAssign, Sub, SubAssign};
use num_bigint::BigInt;
use serde::{Deserialize, Serialize};
use std::{
fmt,
iter::{Product, Sum},
ops::{Div, DivAssign, Mul, MulAssign, Neg},
str::FromStr,
};
#[derive(
Add,
AddAssign,
CandidType,
Clone,
Debug,
Default,
Eq,
PartialEq,
Hash,
Ord,
PartialOrd,
Serialize,
Deserialize,
Sub,
SubAssign,
)]
pub struct IntBig(WrappedInt);
impl IntBig {
#[must_use]
pub const fn from_candid(value: WrappedInt) -> Self {
Self(value)
}
#[must_use]
pub fn from_bigint(value: BigInt) -> Self {
Self::from_candid(WrappedInt::from(value))
}
#[must_use]
pub fn sign_and_u32_digits(&self) -> (bool, Vec<u32>) {
(
self.0.0.cmp(&0.into()).is_lt(),
self.0.0.magnitude().to_u32_digits(),
)
}
#[must_use]
pub fn to_i128(&self) -> Option<i128> {
let big = &self.0.0;
i128::try_from(big).ok()
}
#[must_use]
pub fn to_i64(&self) -> Option<i64> {
let big = &self.0.0;
i64::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 signed LEB128 encoding failed");
out
}
pub(crate) fn to_sign_and_magnitude_bytes(&self) -> (bool, Vec<u8>) {
let (sign, magnitude) = self.0.0.to_bytes_be();
(sign == num_bigint::Sign::Minus, magnitude)
}
pub(crate) fn from_sign_and_magnitude_bytes(negative: bool, magnitude: &[u8]) -> Self {
let sign = if magnitude.is_empty() {
num_bigint::Sign::NoSign
} else if negative {
num_bigint::Sign::Minus
} else {
num_bigint::Sign::Plus
};
Self::from_bigint(BigInt::from_bytes_be(sign, 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 {
Self(self.0 - rhs.0)
}
}
impl fmt::Display for IntBig {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
impl FromStr for IntBig {
type Err = <WrappedInt as FromStr>::Err;
fn from_str(s: &str) -> Result<Self, Self::Err> {
WrappedInt::from_str(s).map(Self::from_candid)
}
}
impl Div for IntBig {
type Output = Self;
fn div(self, other: Self) -> Self::Output {
Self(self.0 / other.0)
}
}
impl DivAssign for IntBig {
fn div_assign(&mut self, other: Self) {
self.0 /= other.0;
}
}
impl From<i32> for IntBig {
fn from(n: i32) -> Self {
Self::from_candid(WrappedInt::from(n))
}
}
impl From<i64> for IntBig {
fn from(n: i64) -> Self {
Self::from_candid(WrappedInt::from(n))
}
}
impl Mul for IntBig {
type Output = Self;
fn mul(self, other: Self) -> Self::Output {
Self(self.0 * other.0)
}
}
impl MulAssign for IntBig {
fn mul_assign(&mut self, other: Self) {
self.0 *= other.0;
}
}
impl Neg for IntBig {
type Output = Self;
fn neg(self) -> Self::Output {
Self::from_bigint(-self.0.0)
}
}
impl NumericValue for IntBig {
fn try_to_decimal(&self) -> Option<Decimal> {
self.to_i128().and_then(Decimal::from_i128)
}
fn try_from_decimal(value: Decimal) -> Option<Self> {
value.to_i128().map(WrappedInt::from).map(Self::from_candid)
}
}
impl Product for IntBig {
fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
iter.fold(Self::from(1), |acc, value| acc * value)
}
}
impl Sum for IntBig {
fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
iter.fold(Self::default(), |acc, x| acc + x)
}
}