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 fn leb128_len(&self) -> u64 {
49 let bits = self.magnitude_bits();
50 let negative_boundary = self.0.0.sign() == num_bigint::Sign::Minus
54 && bits.is_multiple_of(7)
55 && self.0.0.trailing_zeros() == Some(bits.saturating_sub(1));
56 bits / 7 + 1 - u64::from(negative_boundary)
57 }
58
59 #[must_use]
61 pub const fn from_candid(value: WrappedInt) -> Self {
62 Self(value)
63 }
64
65 #[must_use]
67 pub fn from_bigint(value: BigInt) -> Self {
68 Self::from_candid(WrappedInt::from(value))
69 }
70
71 #[must_use]
73 pub fn sign_and_u32_digits(
74 &self,
75 ) -> (
76 bool,
77 impl DoubleEndedIterator<Item = u32> + ExactSizeIterator + '_,
78 ) {
79 (
80 self.0.0.sign() == num_bigint::Sign::Minus,
81 self.0.0.magnitude().iter_u32_digits(),
82 )
83 }
84
85 #[must_use]
87 pub fn to_i128(&self) -> Option<i128> {
88 let big = &self.0.0;
89
90 i128::try_from(big).ok()
91 }
92
93 #[must_use]
95 pub fn to_i64(&self) -> Option<i64> {
96 let big = &self.0.0;
97
98 i64::try_from(big).ok()
99 }
100
101 #[must_use]
103 pub fn to_leb128(&self) -> Vec<u8> {
104 self.leb128_bytes().collect()
105 }
106
107 pub fn leb128_bytes(&self) -> impl Iterator<Item = u8> + '_ {
109 let (negative, limbs) = self.sign_and_u32_digits();
110 crate::leb128::bytes(limbs, negative, self.leb128_len())
111 }
112
113 pub(crate) fn to_sign_and_magnitude_bytes(&self) -> (bool, Vec<u8>) {
114 let (sign, magnitude) = self.0.0.to_bytes_be();
115 (sign == num_bigint::Sign::Minus, magnitude)
116 }
117
118 pub(crate) fn from_sign_and_magnitude_bytes(negative: bool, magnitude: &[u8]) -> Self {
119 let sign = if magnitude.is_empty() {
120 num_bigint::Sign::NoSign
121 } else if negative {
122 num_bigint::Sign::Minus
123 } else {
124 num_bigint::Sign::Plus
125 };
126 Self::from_bigint(BigInt::from_bytes_be(sign, magnitude))
127 }
128
129 #[must_use]
131 pub fn saturating_add(self, rhs: Self) -> Self {
132 Self(self.0 + rhs.0)
133 }
134
135 #[must_use]
137 pub fn saturating_sub(self, rhs: Self) -> Self {
138 Self(self.0 - rhs.0)
139 }
140}
141
142impl fmt::Display for IntBig {
143 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
144 self.0.fmt(f)
145 }
146}
147
148impl FromStr for IntBig {
149 type Err = <WrappedInt as FromStr>::Err;
150
151 fn from_str(s: &str) -> Result<Self, Self::Err> {
152 WrappedInt::from_str(s).map(Self::from_candid)
153 }
154}
155
156impl Div for IntBig {
157 type Output = Self;
158
159 fn div(self, other: Self) -> Self::Output {
160 Self(self.0 / other.0)
161 }
162}
163
164impl DivAssign for IntBig {
165 fn div_assign(&mut self, other: Self) {
166 self.0 /= other.0;
167 }
168}
169
170impl From<i32> for IntBig {
171 fn from(n: i32) -> Self {
172 Self::from_candid(WrappedInt::from(n))
173 }
174}
175
176impl From<i64> for IntBig {
177 fn from(n: i64) -> Self {
178 Self::from_candid(WrappedInt::from(n))
179 }
180}
181
182impl Mul for IntBig {
183 type Output = Self;
184
185 fn mul(self, other: Self) -> Self::Output {
186 Self(self.0 * other.0)
187 }
188}
189
190impl MulAssign for IntBig {
191 fn mul_assign(&mut self, other: Self) {
192 self.0 *= other.0;
193 }
194}
195
196impl Neg for IntBig {
197 type Output = Self;
198
199 fn neg(self) -> Self::Output {
200 Self::from_bigint(-self.0.0)
201 }
202}
203
204impl NumericValue for IntBig {
205 fn try_to_decimal(&self) -> Option<Decimal> {
206 self.to_i128().and_then(Decimal::from_i128)
207 }
208
209 fn try_from_decimal(value: Decimal) -> Option<Self> {
210 value.to_i128().map(WrappedInt::from).map(Self::from_candid)
211 }
212}
213
214impl Product for IntBig {
215 fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
216 iter.fold(Self::from(1), |acc, value| acc * value)
217 }
218}
219
220impl Sum for IntBig {
221 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
222 iter.fold(Self::default(), |acc, x| acc + x)
223 }
224}