1use crate::{Decimal, NumericValue};
4use candid::{CandidType, Int as WrappedInt};
5use derive_more::{Add, AddAssign, Sub, SubAssign};
6use num_bigint::BigInt;
7use serde::{Deserialize, Serialize};
8use std::{
9 fmt,
10 iter::{Product, Sum},
11 ops::{Div, DivAssign, Mul, MulAssign, Neg},
12 str::FromStr,
13};
14
15#[derive(
20 Add,
21 AddAssign,
22 CandidType,
23 Clone,
24 Debug,
25 Default,
26 Eq,
27 PartialEq,
28 Hash,
29 Ord,
30 PartialOrd,
31 Serialize,
32 Deserialize,
33 Sub,
34 SubAssign,
35)]
36pub struct IntBig(WrappedInt);
38
39impl IntBig {
40 #[must_use]
42 pub fn magnitude_bits(&self) -> u64 {
43 self.0.0.bits()
44 }
45
46 #[must_use]
48 pub const fn from_candid(value: WrappedInt) -> Self {
49 Self(value)
50 }
51
52 #[must_use]
54 pub fn from_bigint(value: BigInt) -> Self {
55 Self::from_candid(WrappedInt::from(value))
56 }
57
58 #[must_use]
62 pub fn sign_and_u32_digits(&self) -> (bool, Vec<u32>) {
63 (
64 self.0.0.cmp(&0.into()).is_lt(),
65 self.0.0.magnitude().to_u32_digits(),
66 )
67 }
68
69 #[must_use]
71 pub fn to_i128(&self) -> Option<i128> {
72 let big = &self.0.0;
73
74 i128::try_from(big).ok()
75 }
76
77 #[must_use]
79 pub fn to_i64(&self) -> Option<i64> {
80 let big = &self.0.0;
81
82 i64::try_from(big).ok()
83 }
84
85 #[must_use]
87 pub fn to_leb128(&self) -> Vec<u8> {
88 let mut out = Vec::new();
89 let encoded = self.0.encode(&mut out);
90 debug_assert!(encoded.is_ok(), "Vec-backed signed LEB128 encoding failed");
91
92 out
93 }
94
95 pub(crate) fn to_sign_and_magnitude_bytes(&self) -> (bool, Vec<u8>) {
96 let (sign, magnitude) = self.0.0.to_bytes_be();
97 (sign == num_bigint::Sign::Minus, magnitude)
98 }
99
100 pub(crate) fn from_sign_and_magnitude_bytes(negative: bool, magnitude: &[u8]) -> Self {
101 let sign = if magnitude.is_empty() {
102 num_bigint::Sign::NoSign
103 } else if negative {
104 num_bigint::Sign::Minus
105 } else {
106 num_bigint::Sign::Plus
107 };
108 Self::from_bigint(BigInt::from_bytes_be(sign, magnitude))
109 }
110
111 #[must_use]
113 pub fn saturating_add(self, rhs: Self) -> Self {
114 Self(self.0 + rhs.0)
115 }
116
117 #[must_use]
119 pub fn saturating_sub(self, rhs: Self) -> Self {
120 Self(self.0 - rhs.0)
121 }
122}
123
124impl fmt::Display for IntBig {
125 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
126 self.0.fmt(f)
127 }
128}
129
130impl FromStr for IntBig {
131 type Err = <WrappedInt as FromStr>::Err;
132
133 fn from_str(s: &str) -> Result<Self, Self::Err> {
134 WrappedInt::from_str(s).map(Self::from_candid)
135 }
136}
137
138impl Div for IntBig {
139 type Output = Self;
140
141 fn div(self, other: Self) -> Self::Output {
142 Self(self.0 / other.0)
143 }
144}
145
146impl DivAssign for IntBig {
147 fn div_assign(&mut self, other: Self) {
148 self.0 /= other.0;
149 }
150}
151
152impl From<i32> for IntBig {
153 fn from(n: i32) -> Self {
154 Self::from_candid(WrappedInt::from(n))
155 }
156}
157
158impl From<i64> for IntBig {
159 fn from(n: i64) -> Self {
160 Self::from_candid(WrappedInt::from(n))
161 }
162}
163
164impl Mul for IntBig {
165 type Output = Self;
166
167 fn mul(self, other: Self) -> Self::Output {
168 Self(self.0 * other.0)
169 }
170}
171
172impl MulAssign for IntBig {
173 fn mul_assign(&mut self, other: Self) {
174 self.0 *= other.0;
175 }
176}
177
178impl Neg for IntBig {
179 type Output = Self;
180
181 fn neg(self) -> Self::Output {
182 Self::from_bigint(-self.0.0)
183 }
184}
185
186impl NumericValue for IntBig {
187 fn try_to_decimal(&self) -> Option<Decimal> {
188 self.to_i128().and_then(Decimal::from_i128)
189 }
190
191 fn try_from_decimal(value: Decimal) -> Option<Self> {
192 value.to_i128().map(WrappedInt::from).map(Self::from_candid)
193 }
194}
195
196impl Product for IntBig {
197 fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
198 iter.fold(Self::from(1), |acc, value| acc * value)
199 }
200}
201
202impl Sum for IntBig {
203 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
204 iter.fold(Self::default(), |acc, x| acc + x)
205 }
206}