1use alloc::vec::Vec;
2use core::ops::{Add, Div, Mul, Rem, Sub};
3use core::ops::{AddAssign, DivAssign, MulAssign, RemAssign, SubAssign};
4use core::ops::{BitAnd, BitOr, BitXor, Shl, Shr};
5use core::ops::{BitAndAssign, BitOrAssign, BitXorAssign, ShlAssign, ShrAssign};
6use numbat_wasm::BigUintApi;
7
8use core::cmp::Ordering;
9use num_bigint::{BigInt, BigUint, Sign};
10
11#[derive(Debug)]
12pub struct RustBigUint(pub num_bigint::BigInt);
13
14impl RustBigUint {
15 pub fn value(&self) -> BigUint {
16 self.0.to_biguint().unwrap()
17 }
18}
19
20impl From<u64> for RustBigUint {
21 fn from(item: u64) -> Self {
22 RustBigUint(BigUint::from(item).into())
23 }
24}
25
26impl From<u32> for RustBigUint {
27 fn from(item: u32) -> Self {
28 RustBigUint(BigUint::from(item).into())
29 }
30}
31
32impl From<usize> for RustBigUint {
33 fn from(item: usize) -> Self {
34 RustBigUint(BigUint::from(item).into())
35 }
36}
37
38impl From<BigInt> for RustBigUint {
39 fn from(item: BigInt) -> Self {
40 RustBigUint(item)
41 }
42}
43
44impl From<BigUint> for RustBigUint {
45 fn from(item: BigUint) -> Self {
46 RustBigUint(BigInt::from_biguint(Sign::Plus, item))
47 }
48}
49
50impl Clone for RustBigUint {
51 fn clone(&self) -> Self {
52 RustBigUint(self.0.clone())
53 }
54}
55
56macro_rules! binary_operator {
57 ($trait:ident, $method:ident) => {
58 impl $trait for RustBigUint {
59 type Output = RustBigUint;
60
61 fn $method(self, other: RustBigUint) -> RustBigUint {
62 RustBigUint((self.0).$method(other.0))
63 }
64 }
65
66 impl<'a, 'b> $trait<&'b RustBigUint> for &'a RustBigUint {
67 type Output = RustBigUint;
68
69 fn $method(self, other: &RustBigUint) -> RustBigUint {
70 RustBigUint(self.0.clone().$method(other.0.clone()))
71 }
72 }
73 };
74}
75
76binary_operator! {Add, add}
77binary_operator! {Mul, mul}
78binary_operator! {Div, div}
79binary_operator! {Rem, rem}
80
81binary_operator! {BitAnd, bitand}
82binary_operator! {BitOr, bitor}
83binary_operator! {BitXor, bitxor}
84
85fn check_sub_result(result: &BigInt) {
86 if result.sign() == num_bigint::Sign::Minus {
87 panic!(b"Cannot subtract because result would be negative")
88 }
89}
90
91impl Sub for RustBigUint {
92 type Output = RustBigUint;
93
94 fn sub(self, other: RustBigUint) -> RustBigUint {
95 let result = self.0 - other.0;
96 check_sub_result(&result);
97 RustBigUint(result)
98 }
99}
100
101impl<'a, 'b> Sub<&'b RustBigUint> for &'a RustBigUint {
102 type Output = RustBigUint;
103
104 fn sub(self, other: &RustBigUint) -> RustBigUint {
105 let result = self.0.clone().sub(other.0.clone());
106 check_sub_result(&result);
107 RustBigUint(result)
108 }
109}
110
111macro_rules! binary_assign_operator {
112 ($trait:ident, $method:ident) => {
113 impl $trait<RustBigUint> for RustBigUint {
114 fn $method(&mut self, other: Self) {
115 BigInt::$method(&mut self.0, other.0);
116 }
117 }
118
119 impl $trait<&RustBigUint> for RustBigUint {
120 fn $method(&mut self, other: &RustBigUint) {
121 BigInt::$method(&mut self.0, &other.0);
122 }
123 }
124 };
125}
126
127binary_assign_operator! {AddAssign, add_assign}
128binary_assign_operator! {MulAssign, mul_assign}
129binary_assign_operator! {DivAssign, div_assign}
130binary_assign_operator! {RemAssign, rem_assign}
131
132binary_assign_operator! {BitAndAssign, bitand_assign}
133binary_assign_operator! {BitOrAssign, bitor_assign}
134binary_assign_operator! {BitXorAssign, bitxor_assign}
135
136impl SubAssign<RustBigUint> for RustBigUint {
137 fn sub_assign(&mut self, other: Self) {
138 BigInt::sub_assign(&mut self.0, other.0);
139 check_sub_result(&self.0);
140 }
141}
142
143impl SubAssign<&RustBigUint> for RustBigUint {
144 fn sub_assign(&mut self, other: &RustBigUint) {
145 BigInt::sub_assign(&mut self.0, &other.0);
146 check_sub_result(&self.0);
147 }
148}
149
150macro_rules! shift_traits {
151 ($shift_trait:ident, $method:ident) => {
152 impl $shift_trait<usize> for RustBigUint {
153 type Output = RustBigUint;
154
155 fn $method(self, rhs: usize) -> RustBigUint {
156 let result = $shift_trait::$method(self.0, rhs);
157 RustBigUint(result)
158 }
159 }
160
161 impl<'a> $shift_trait<usize> for &'a RustBigUint {
162 type Output = RustBigUint;
163
164 fn $method(self, rhs: usize) -> RustBigUint {
165 let result = $shift_trait::$method(&self.0, rhs);
166 RustBigUint(result)
167 }
168 }
169 };
170}
171
172shift_traits! {Shl, shl}
173shift_traits! {Shr, shr}
174
175macro_rules! shift_assign_traits {
176 ($shift_assign_trait:ident, $method:ident) => {
177 impl $shift_assign_trait<usize> for RustBigUint {
178 fn $method(&mut self, rhs: usize) {
179 $shift_assign_trait::$method(&mut self.0, rhs);
180 }
181 }
182 };
183}
184
185shift_assign_traits! {ShlAssign, shl_assign}
186shift_assign_traits! {ShrAssign, shr_assign}
187
188impl PartialEq<Self> for RustBigUint {
189 #[inline]
190 fn eq(&self, other: &Self) -> bool {
191 PartialEq::eq(&self.0, &other.0)
192 }
193}
194
195impl Eq for RustBigUint {}
196
197impl PartialOrd<Self> for RustBigUint {
198 #[inline]
199 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
200 PartialOrd::partial_cmp(&self.0, &other.0)
201 }
202}
203
204impl Ord for RustBigUint {
205 #[inline]
206 fn cmp(&self, other: &Self) -> Ordering {
207 Ord::cmp(&self.0, &other.0)
208 }
209}
210
211impl PartialEq<u64> for RustBigUint {
212 #[inline]
213 fn eq(&self, other: &u64) -> bool {
214 PartialEq::eq(&self.0, &BigInt::from(*other as i64))
215 }
216}
217
218impl PartialOrd<u64> for RustBigUint {
219 #[inline]
220 fn partial_cmp(&self, other: &u64) -> Option<Ordering> {
221 PartialOrd::partial_cmp(&self.0, &BigInt::from(*other as i64))
222 }
223}
224
225use numbat_wasm::numbat_codec::*;
226
227impl NestedEncode for RustBigUint {
228 const TYPE_INFO: TypeInfo = TypeInfo::BigUint;
229
230 fn dep_encode<O: NestedEncodeOutput>(&self, dest: &mut O) -> Result<(), EncodeError> {
231 self.to_bytes_be().as_slice().dep_encode(dest)
232 }
233
234 fn dep_encode_or_exit<O: NestedEncodeOutput, ExitCtx: Clone>(
235 &self,
236 dest: &mut O,
237 c: ExitCtx,
238 exit: fn(ExitCtx, EncodeError) -> !,
239 ) {
240 self.to_bytes_be()
241 .as_slice()
242 .dep_encode_or_exit(dest, c, exit);
243 }
244}
245
246impl TopEncode for RustBigUint {
247 const TYPE_INFO: TypeInfo = TypeInfo::BigUint;
248
249 fn top_encode<O: TopEncodeOutput>(&self, output: O) -> Result<(), EncodeError> {
250 self.to_bytes_be().top_encode(output)
251 }
252
253 fn top_encode_or_exit<O: TopEncodeOutput, ExitCtx: Clone>(
254 &self,
255 output: O,
256 c: ExitCtx,
257 exit: fn(ExitCtx, EncodeError) -> !,
258 ) {
259 self.to_bytes_be().top_encode_or_exit(output, c, exit)
260 }
261}
262
263impl NestedDecode for RustBigUint {
264 const TYPE_INFO: TypeInfo = TypeInfo::BigUint;
265
266 fn dep_decode<I: NestedDecodeInput>(input: &mut I) -> Result<Self, DecodeError> {
267 let size = usize::dep_decode(input)?;
268 let bytes = input.read_slice(size)?;
269 Ok(RustBigUint::from_bytes_be(bytes))
270 }
271
272 fn dep_decode_or_exit<I: NestedDecodeInput, ExitCtx: Clone>(
273 input: &mut I,
274 c: ExitCtx,
275 exit: fn(ExitCtx, DecodeError) -> !,
276 ) -> Self {
277 let size = usize::dep_decode_or_exit(input, c.clone(), exit);
278 let bytes = input.read_slice_or_exit(size, c, exit);
279 RustBigUint::from_bytes_be(bytes)
280 }
281}
282
283impl TopDecode for RustBigUint {
284 const TYPE_INFO: TypeInfo = TypeInfo::BigUint;
285
286 fn top_decode<I: TopDecodeInput>(input: I) -> Result<Self, DecodeError> {
287 Ok(RustBigUint::from_bytes_be(&*input.into_boxed_slice_u8()))
288 }
289
290 fn top_decode_or_exit<I: TopDecodeInput, ExitCtx: Clone>(
291 input: I,
292 _: ExitCtx,
293 _: fn(ExitCtx, DecodeError) -> !,
294 ) -> Self {
295 RustBigUint::from_bytes_be(&*input.into_boxed_slice_u8())
296 }
297}
298
299impl numbat_wasm::abi::TypeAbi for RustBigUint {
300 fn type_name() -> String {
301 String::from("BigUint")
302 }
303}
304
305impl numbat_wasm::BigUintApi for RustBigUint {
306 fn byte_length(&self) -> i32 {
307 panic!("byte_length not yet implemented")
308 }
309
310 fn copy_to_slice_big_endian(&self, _slice: &mut [u8]) -> i32 {
311 panic!("copy_to_slice not yet implemented")
312 }
313
314 fn copy_to_array_big_endian_pad_right(&self, target: &mut [u8; 32]) {
315 if self.0.sign() == Sign::Plus {
316 let (_, bytes) = self.0.to_bytes_be();
317 let offset = 32 - bytes.len();
318 target[offset..].clone_from_slice(&bytes[..]);
319 }
320 }
321
322 fn to_bytes_be(&self) -> Vec<u8> {
323 if self.0.sign() == Sign::NoSign {
324 Vec::new()
325 } else {
326 let (_, be) = self.0.to_bytes_be();
327 be
328 }
329 }
330
331 fn to_bytes_be_pad_right(&self, nr_bytes: usize) -> Option<Vec<u8>> {
332 let (_, bytes_be) = self.0.to_bytes_be();
333 match bytes_be.len().cmp(&nr_bytes) {
334 Ordering::Greater => None,
335 Ordering::Equal => Some(bytes_be),
336 Ordering::Less => {
337 let mut res = vec![0u8; nr_bytes];
338 let offset = nr_bytes - bytes_be.len();
339 res[offset..].clone_from_slice(&bytes_be[..]);
340 Some(res)
341 },
342 }
343 }
344
345 fn from_bytes_be(bytes: &[u8]) -> Self {
346 let bi = BigInt::from_bytes_be(num_bigint::Sign::Plus, bytes);
347 bi.into()
348 }
349}