1use crate::{
4 Decimal, NumericValue,
5 integer_wire::{self, IntegerWire},
6};
7use candid::{CandidType, Int as WrappedInt};
8use derive_more::{Add, AddAssign, Sub, SubAssign};
9use num_bigint::BigInt;
10use serde::{Deserialize, Serialize};
11use std::{
12 fmt,
13 iter::{Product, Sum},
14 ops::{Div, DivAssign, Mul, MulAssign, Neg},
15 str::FromStr,
16};
17
18#[derive(
23 Add,
24 AddAssign,
25 CandidType,
26 Clone,
27 Debug,
28 Default,
29 Eq,
30 PartialEq,
31 Hash,
32 Ord,
33 PartialOrd,
34 Sub,
35 SubAssign,
36)]
37pub struct IntBig(WrappedInt);
42
43impl IntBig {
44 #[must_use]
46 pub fn magnitude_bits(&self) -> u64 {
47 self.0.0.bits()
48 }
49
50 #[must_use]
52 pub fn leb128_len(&self) -> u64 {
53 let bits = self.magnitude_bits();
54 let negative_boundary = self.0.0.sign() == num_bigint::Sign::Minus
58 && bits.is_multiple_of(7)
59 && self.0.0.trailing_zeros() == Some(bits.saturating_sub(1));
60 bits / 7 + 1 - u64::from(negative_boundary)
61 }
62
63 #[must_use]
65 pub const fn from_candid(value: WrappedInt) -> Self {
66 Self(value)
67 }
68
69 #[must_use]
71 pub fn from_bigint(value: BigInt) -> Self {
72 Self::from_candid(WrappedInt::from(value))
73 }
74
75 #[must_use]
77 pub fn sign_and_u32_digits(
78 &self,
79 ) -> (
80 bool,
81 impl DoubleEndedIterator<Item = u32> + ExactSizeIterator + '_,
82 ) {
83 (
84 self.0.0.sign() == num_bigint::Sign::Minus,
85 self.0.0.magnitude().iter_u32_digits(),
86 )
87 }
88
89 #[must_use]
91 pub fn to_i128(&self) -> Option<i128> {
92 let big = &self.0.0;
93
94 i128::try_from(big).ok()
95 }
96
97 #[must_use]
99 pub fn to_i64(&self) -> Option<i64> {
100 let big = &self.0.0;
101
102 i64::try_from(big).ok()
103 }
104
105 #[must_use]
107 pub fn to_leb128(&self) -> Vec<u8> {
108 self.leb128_bytes().collect()
109 }
110
111 pub fn leb128_bytes(&self) -> impl Iterator<Item = u8> + '_ {
113 let (negative, limbs) = self.sign_and_u32_digits();
114 crate::leb128::bytes(limbs, negative, self.leb128_len())
115 }
116
117 pub(crate) fn to_sign_and_magnitude_bytes(&self) -> (bool, Vec<u8>) {
118 let (sign, magnitude) = self.0.0.to_bytes_be();
119 (sign == num_bigint::Sign::Minus, magnitude)
120 }
121
122 pub(crate) fn from_sign_and_magnitude_bytes(negative: bool, magnitude: &[u8]) -> Self {
123 let sign = if magnitude.is_empty() {
124 num_bigint::Sign::NoSign
125 } else if negative {
126 num_bigint::Sign::Minus
127 } else {
128 num_bigint::Sign::Plus
129 };
130 Self::from_bigint(BigInt::from_bytes_be(sign, magnitude))
131 }
132
133 #[must_use]
135 pub fn saturating_add(self, rhs: Self) -> Self {
136 Self(self.0 + rhs.0)
137 }
138
139 #[must_use]
141 pub fn saturating_sub(self, rhs: Self) -> Self {
142 Self(self.0 - rhs.0)
143 }
144}
145
146impl<'de> Deserialize<'de> for IntBig {
147 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
148 integer_wire::deserialize_integer(deserializer)
149 }
150}
151
152impl fmt::Display for IntBig {
153 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
154 self.0.fmt(f)
155 }
156}
157
158impl FromStr for IntBig {
159 type Err = <WrappedInt as FromStr>::Err;
160
161 fn from_str(s: &str) -> Result<Self, Self::Err> {
162 WrappedInt::from_str(s).map(Self::from_candid)
163 }
164}
165
166impl Div for IntBig {
167 type Output = Self;
168
169 fn div(self, other: Self) -> Self::Output {
170 Self(self.0 / other.0)
171 }
172}
173
174impl DivAssign for IntBig {
175 fn div_assign(&mut self, other: Self) {
176 self.0 /= other.0;
177 }
178}
179
180impl From<i32> for IntBig {
181 fn from(n: i32) -> Self {
182 Self::from_candid(WrappedInt::from(n))
183 }
184}
185
186impl From<i64> for IntBig {
187 fn from(n: i64) -> Self {
188 Self::from_candid(WrappedInt::from(n))
189 }
190}
191
192impl IntegerWire for IntBig {
193 fn from_signed(value: i64) -> Option<Self> {
194 Some(Self::from(value))
195 }
196
197 fn from_unsigned(value: u64) -> Self {
198 Self::from_candid(WrappedInt::from(value))
199 }
200
201 fn from_wire_bytes(value: &[u8]) -> Option<Self> {
202 integer_wire::signed_body(value)
203 .map(|body| Self::from_bigint(BigInt::from_signed_bytes_le(body)))
204 }
205}
206
207impl Mul for IntBig {
208 type Output = Self;
209
210 fn mul(self, other: Self) -> Self::Output {
211 Self(self.0 * other.0)
212 }
213}
214
215impl MulAssign for IntBig {
216 fn mul_assign(&mut self, other: Self) {
217 self.0 *= other.0;
218 }
219}
220
221impl Neg for IntBig {
222 type Output = Self;
223
224 fn neg(self) -> Self::Output {
225 Self::from_bigint(-self.0.0)
226 }
227}
228
229impl NumericValue for IntBig {
230 fn try_to_decimal(&self) -> Option<Decimal> {
231 self.to_i128().and_then(Decimal::from_i128)
232 }
233
234 fn try_from_decimal(value: Decimal) -> Option<Self> {
235 value.to_i128().map(WrappedInt::from).map(Self::from_candid)
236 }
237}
238
239impl Product for IntBig {
240 fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
241 iter.fold(Self::from(1), |acc, value| acc * value)
242 }
243}
244
245impl Serialize for IntBig {
246 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
247 if serializer.is_human_readable() {
248 return serializer.collect_str(&self.0.0);
249 }
250 if let Some(value) = self.to_i64() {
251 return serializer.serialize_i64(value);
252 }
253 if let Ok(value) = u64::try_from(&self.0.0) {
254 return serializer.serialize_u64(value);
255 }
256 let (negative, limbs) = self.sign_and_u32_digits();
257 serializer.serialize_bytes(&integer_wire::signed_bytes(negative, limbs))
258 }
259}
260
261impl Sum for IntBig {
262 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
263 iter.fold(Self::default(), |acc, x| acc + x)
264 }
265}