multiversx_sc/types/managed/basic/
big_int.rs1use core::{convert::TryInto, marker::PhantomData};
2
3use crate::{
4 abi::{TypeAbiFrom, TypeName},
5 api::{
6 BigIntApiImpl, HandleConstraints, ManagedBufferApiImpl, ManagedTypeApi, ManagedTypeApiImpl,
7 RawHandle, StaticVarApiImpl, const_handles, use_raw_handle,
8 },
9 codec::{
10 DecodeErrorHandler, EncodeErrorHandler, NestedDecode, NestedDecodeInput, NestedEncode,
11 NestedEncodeOutput, TopDecode, TopDecodeInput, TopEncode, TopEncodeOutput, TryStaticCast,
12 },
13 formatter::{FormatByteReceiver, SCDisplay, hex_util::encode_bytes_as_hex},
14 types::{
15 BigUint, ManagedBuffer, ManagedOption, ManagedRef, ManagedType, Sign, heap::BoxedBytes,
16 },
17};
18
19use super::cast_to_i64::cast_to_i64;
20
21#[repr(transparent)]
22pub struct BigInt<M: ManagedTypeApi> {
23 pub(crate) handle: M::BigIntHandle,
24 _phantom: PhantomData<M>,
25}
26
27impl<M: ManagedTypeApi> ManagedType<M> for BigInt<M> {
28 type OwnHandle = M::BigIntHandle;
29
30 unsafe fn from_handle(handle: M::BigIntHandle) -> Self {
31 BigInt {
32 handle,
33 _phantom: PhantomData,
34 }
35 }
36
37 fn get_handle(&self) -> M::BigIntHandle {
38 self.handle.clone()
39 }
40
41 unsafe fn forget_into_handle(self) -> Self::OwnHandle {
42 unsafe {
43 let handle = core::ptr::read(&self.handle);
44 core::mem::forget(self);
45 handle
46 }
47 }
48
49 fn transmute_from_handle_ref(handle_ref: &M::BigIntHandle) -> &Self {
50 unsafe { core::mem::transmute(handle_ref) }
51 }
52
53 fn transmute_from_handle_ref_mut(handle_ref: &mut M::BigIntHandle) -> &mut Self {
54 unsafe { core::mem::transmute(handle_ref) }
55 }
56}
57
58impl<M: ManagedTypeApi> Default for BigInt<M> {
59 #[inline]
60 fn default() -> Self {
61 Self::zero()
62 }
63}
64
65impl<M: ManagedTypeApi> From<&ManagedBuffer<M>> for BigInt<M> {
66 #[inline]
67 fn from(item: &ManagedBuffer<M>) -> Self {
68 BigInt::from_signed_bytes_be_buffer(item)
69 }
70}
71
72impl<M: ManagedTypeApi> From<ManagedBuffer<M>> for BigInt<M> {
73 #[inline]
74 fn from(item: ManagedBuffer<M>) -> Self {
75 BigInt::from_signed_bytes_be_buffer(&item)
76 }
77}
78
79impl<M: ManagedTypeApi> BigInt<M> {
80 pub unsafe fn new_uninit() -> Self {
86 unsafe {
87 let new_handle: M::BigIntHandle =
88 use_raw_handle(M::static_var_api_impl().next_handle());
89 BigInt::from_handle(new_handle)
90 }
91 }
92
93 pub(crate) fn set_value<T>(handle: M::BigIntHandle, value: T)
94 where
95 T: TryInto<i64>,
96 {
97 M::managed_type_impl().bi_set_int64(handle, cast_to_i64::<M, _>(value));
98 }
99
100 pub(crate) fn make_temp<T>(handle: RawHandle, value: T) -> M::BigIntHandle
101 where
102 T: TryInto<i64>,
103 {
104 let temp: M::BigIntHandle = use_raw_handle(handle);
105 Self::set_value(temp.clone(), value);
106 temp
107 }
108}
109
110impl<M: ManagedTypeApi> From<BigUint<M>> for BigInt<M> {
111 #[inline]
112 fn from(item: BigUint<M>) -> Self {
113 item.into_big_int()
114 }
115}
116
117macro_rules! big_int_conv_num {
118 ($num_ty:ty) => {
119 impl<M: ManagedTypeApi> From<$num_ty> for BigInt<M> {
120 #[inline]
121 fn from(value: $num_ty) -> Self {
122 unsafe {
123 let result = BigInt::new_uninit();
124 Self::set_value(result.get_handle(), value);
125 result
126 }
127 }
128 }
129
130 impl<M: ManagedTypeApi> TypeAbiFrom<$num_ty> for BigInt<M> {}
131 impl<M: ManagedTypeApi> TypeAbiFrom<&$num_ty> for BigInt<M> {}
132 };
133}
134
135big_int_conv_num! {i64}
137big_int_conv_num! {i32}
138big_int_conv_num! {isize}
139big_int_conv_num! {i16}
140big_int_conv_num! {i8}
141
142#[cfg(feature = "num-bigint")]
143impl<M: ManagedTypeApi> TypeAbiFrom<crate::codec::num_bigint::BigInt> for BigInt<M> {}
144#[cfg(feature = "num-bigint")]
145impl<M: ManagedTypeApi> TypeAbiFrom<BigInt<M>> for crate::codec::num_bigint::BigInt {}
146
147impl<M> TypeAbiFrom<Self> for BigInt<M> where M: ManagedTypeApi {}
148impl<M> TypeAbiFrom<&Self> for BigInt<M> where M: ManagedTypeApi {}
149
150impl<M: ManagedTypeApi> crate::abi::TypeAbi for BigInt<M> {
151 #[cfg(feature = "num-bigint")]
152 type Unmanaged = crate::codec::num_bigint::BigInt;
153
154 #[cfg(not(feature = "num-bigint"))]
155 type Unmanaged = Self;
156
157 fn type_name() -> TypeName {
158 TypeName::from("BigInt")
159 }
160
161 fn type_name_rust() -> TypeName {
162 TypeName::from("BigInt<$API>")
163 }
164}
165
166#[cfg(feature = "num-bigint")]
167impl<M: ManagedTypeApi> From<&crate::codec::num_bigint::BigInt> for BigInt<M> {
168 fn from(alloc_big_int: &crate::codec::num_bigint::BigInt) -> Self {
169 BigInt::from_signed_bytes_be(alloc_big_int.to_signed_bytes_be().as_slice())
170 }
171}
172#[cfg(feature = "num-bigint")]
173impl<M: ManagedTypeApi> From<crate::codec::num_bigint::BigInt> for BigInt<M> {
174 fn from(alloc_big_int: crate::codec::num_bigint::BigInt) -> Self {
175 BigInt::from(&alloc_big_int)
176 }
177}
178
179impl<M: ManagedTypeApi> BigInt<M> {
180 #[inline]
181 pub fn zero() -> Self {
182 unsafe {
183 let result = BigInt::new_uninit();
184 M::managed_type_impl().bi_set_int64(result.get_handle(), 0);
185 result
186 }
187 }
188
189 #[inline]
190 pub fn to_i64(&self) -> Option<i64> {
191 M::managed_type_impl().bi_to_i64(self.handle.clone())
192 }
193
194 #[inline]
195 pub fn overwrite_i64(&mut self, value: i64) {
196 Self::set_value(self.handle.clone(), value);
197 }
198
199 #[inline]
200 pub fn from_signed_bytes_be(bytes: &[u8]) -> Self {
201 let mb_handle: M::ManagedBufferHandle = use_raw_handle(const_handles::MBUF_TEMPORARY_1);
202 M::managed_type_impl().mb_overwrite(mb_handle.clone(), bytes);
203 unsafe {
204 let result = BigInt::new_uninit();
205 M::managed_type_impl().mb_to_big_int_signed(mb_handle, result.get_handle());
206 result
207 }
208 }
209
210 #[inline]
211 pub fn to_signed_bytes_be(&self) -> BoxedBytes {
212 let mb_handle: M::ManagedBufferHandle = use_raw_handle(const_handles::MBUF_TEMPORARY_1);
213 M::managed_type_impl().mb_from_big_int_signed(self.handle.clone(), mb_handle.clone());
214 M::managed_type_impl().mb_to_boxed_bytes(mb_handle)
215 }
216
217 #[inline]
218 pub fn from_signed_bytes_be_buffer(managed_buffer: &ManagedBuffer<M>) -> Self {
219 unsafe {
220 let result = BigInt::new_uninit();
221 M::managed_type_impl()
222 .mb_to_big_int_signed(managed_buffer.handle.clone(), result.get_handle());
223 result
224 }
225 }
226
227 #[inline]
228 pub fn to_signed_bytes_be_buffer(&self) -> ManagedBuffer<M> {
229 unsafe {
230 let result = ManagedBuffer::new_uninit();
231 M::managed_type_impl().mb_from_big_int_signed(self.handle.clone(), result.get_handle());
232 result
233 }
234 }
235
236 pub(crate) fn clone_to_handle(source_handle: M::BigIntHandle, dest_handle: M::BigIntHandle) {
237 let api = M::managed_type_impl();
238 api.bi_set_int64(dest_handle.clone(), 0);
239 api.bi_add(dest_handle.clone(), dest_handle, source_handle);
240 }
241}
242
243impl<M: ManagedTypeApi> Clone for BigInt<M> {
244 fn clone(&self) -> Self {
245 unsafe {
246 let result = BigInt::new_uninit();
247 BigInt::<M>::clone_to_handle(self.get_handle(), result.get_handle());
248 result
249 }
250 }
251}
252
253impl<M: ManagedTypeApi> BigInt<M> {
254 pub fn from_biguint(sign: Sign, unsigned: BigUint<M>) -> Self {
255 let result = unsigned.into_big_int();
256 if sign.is_minus() {
257 M::managed_type_impl().bi_neg(result.handle.clone(), result.handle.clone());
258 }
259 result
260 }
261
262 pub fn sign(&self) -> Sign {
264 let api = M::managed_type_impl();
265 match api.bi_sign(self.handle.clone()) {
266 crate::api::Sign::Plus => Sign::Plus,
267 crate::api::Sign::NoSign => Sign::NoSign,
268 crate::api::Sign::Minus => Sign::Minus,
269 }
270 }
271
272 pub fn magnitude(&self) -> BigUint<M> {
274 unsafe {
275 let result = BigUint::new_uninit();
276 M::managed_type_impl().bi_abs(result.get_handle(), self.get_handle());
277 result
278 }
279 }
280
281 pub fn to_parts(self) -> (Sign, BigUint<M>) {
284 (self.sign(), self.magnitude())
285 }
286
287 pub unsafe fn into_big_uint_unchecked(self) -> BigUint<M> {
293 BigUint { value: self }
294 }
295
296 pub fn into_big_uint(self) -> ManagedOption<M, BigUint<M>> {
298 if let Sign::Minus = self.sign() {
299 ManagedOption::none()
300 } else {
301 ManagedOption::some(unsafe { self.into_big_uint_unchecked() })
302 }
303 }
304}
305
306impl<M: ManagedTypeApi> TryStaticCast for BigInt<M> {}
307
308impl<M: ManagedTypeApi> TopEncode for BigInt<M> {
309 #[inline]
310 fn top_encode_or_handle_err<O, H>(&self, output: O, h: H) -> Result<(), H::HandledErr>
311 where
312 O: TopEncodeOutput,
313 H: EncodeErrorHandler,
314 {
315 if O::supports_specialized_type::<Self>() {
316 output.set_specialized(self, h)
317 } else {
318 output.set_slice_u8(self.to_signed_bytes_be().as_slice());
319 Ok(())
320 }
321 }
322}
323
324impl<M: ManagedTypeApi> NestedEncode for BigInt<M> {
325 fn dep_encode_or_handle_err<O, H>(&self, dest: &mut O, h: H) -> Result<(), H::HandledErr>
326 where
327 O: NestedEncodeOutput,
328 H: EncodeErrorHandler,
329 {
330 self.to_signed_bytes_be_buffer()
331 .dep_encode_or_handle_err(dest, h)
332 }
333}
334
335impl<M: ManagedTypeApi> NestedDecode for BigInt<M> {
336 fn dep_decode_or_handle_err<I, H>(input: &mut I, h: H) -> Result<Self, H::HandledErr>
337 where
338 I: NestedDecodeInput,
339 H: DecodeErrorHandler,
340 {
341 if I::supports_specialized_type::<Self>() {
342 input.read_specialized((), h)
343 } else {
344 let boxed_bytes = BoxedBytes::dep_decode_or_handle_err(input, h)?;
345 Ok(Self::from_signed_bytes_be(boxed_bytes.as_slice()))
346 }
347 }
348}
349
350impl<M: ManagedTypeApi> TopDecode for BigInt<M> {
351 fn top_decode_or_handle_err<I, H>(input: I, h: H) -> Result<Self, H::HandledErr>
352 where
353 I: TopDecodeInput,
354 H: DecodeErrorHandler,
355 {
356 if I::supports_specialized_type::<Self>() {
357 input.into_specialized(h)
358 } else {
359 let boxed_bytes = BoxedBytes::top_decode_or_handle_err(input, h)?;
360 Ok(Self::from_signed_bytes_be(boxed_bytes.as_slice()))
361 }
362 }
363}
364
365impl<M: ManagedTypeApi> BigInt<M> {
366 #[must_use]
367 pub fn pow(&self, exp: u32) -> Self {
368 let exp_handle = BigUint::<M>::make_temp(const_handles::BIG_INT_TEMPORARY_1, exp);
369 unsafe {
370 let result = BigInt::new_uninit();
371 M::managed_type_impl().bi_pow(result.get_handle(), self.get_handle(), exp_handle);
372 result
373 }
374 }
375
376 pub fn into_proportion(mut self, part: i64, total: i64) -> Self {
385 let mut temp = BigInt::from(part);
386 self *= &temp;
387 temp.overwrite_i64(total);
388 self /= &temp;
389 self
390 }
391
392 pub fn proportion(&self, part: i64, total: i64) -> Self {
401 self.clone().into_proportion(part, total)
402 }
403
404 pub fn to_display(&self) -> ManagedBuffer<M> {
406 unsafe {
407 let result = ManagedBuffer::<M>::new_uninit();
408 M::managed_type_impl().bi_to_string(self.handle.clone(), result.handle.clone());
409 result
410 }
411 }
412}
413
414impl<M: ManagedTypeApi> SCDisplay for BigInt<M> {
415 fn fmt<F: FormatByteReceiver>(&self, f: &mut F) {
416 let str_handle: M::ManagedBufferHandle = use_raw_handle(const_handles::MBUF_TEMPORARY_1);
417 M::managed_type_impl().bi_to_string(self.handle.clone(), str_handle.clone());
418 let cast_handle = str_handle.cast_or_signal_error::<M, _>();
419 let wrap_cast = unsafe { ManagedRef::wrap_handle(cast_handle) };
420 f.append_managed_buffer(&wrap_cast);
421 }
422}
423
424#[cfg(feature = "alloc")]
425impl<M: ManagedTypeApi> core::fmt::Display for BigInt<M> {
426 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
427 core::fmt::Display::fmt(&self.to_display(), f)
428 }
429}
430
431impl<M: ManagedTypeApi> core::fmt::Debug for BigInt<M> {
432 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
433 f.debug_struct("BigInt")
434 .field("handle", &self.handle.clone())
435 .field(
436 "hex-value-be",
437 &encode_bytes_as_hex(self.to_signed_bytes_be().as_slice()),
438 )
439 .finish()
440 }
441}