multiversx_sc/types/managed/basic/
big_int.rs

1use core::{convert::TryInto, marker::PhantomData};
2
3use crate::{
4    abi::{TypeAbiFrom, TypeName},
5    api::{
6        const_handles, use_raw_handle, BigIntApiImpl, HandleConstraints, ManagedBufferApiImpl,
7        ManagedTypeApi, ManagedTypeApiImpl, RawHandle, StaticVarApiImpl,
8    },
9    codec::{
10        DecodeErrorHandler, EncodeErrorHandler, NestedDecode, NestedDecodeInput, NestedEncode,
11        NestedEncodeOutput, TopDecode, TopDecodeInput, TopEncode, TopEncodeOutput, TryStaticCast,
12    },
13    formatter::{hex_util::encode_bytes_as_hex, FormatByteReceiver, SCDisplay},
14    types::{
15        heap::BoxedBytes, BigUint, ManagedBuffer, ManagedOption, ManagedRef, ManagedType, Sign,
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    /// Creates a new object, without initializing it.
81    ///
82    /// ## Safety
83    ///
84    /// The value needs to be initialized after creation, otherwise the VM will halt the first time the value is attempted to be read.
85    pub unsafe fn new_uninit() -> Self {
86        let new_handle: M::BigIntHandle = use_raw_handle(M::static_var_api_impl().next_handle());
87        BigInt::from_handle(new_handle)
88    }
89
90    pub(crate) fn set_value<T>(handle: M::BigIntHandle, value: T)
91    where
92        T: TryInto<i64>,
93    {
94        M::managed_type_impl().bi_set_int64(handle, cast_to_i64::<M, _>(value));
95    }
96
97    pub(crate) fn make_temp<T>(handle: RawHandle, value: T) -> M::BigIntHandle
98    where
99        T: TryInto<i64>,
100    {
101        let temp: M::BigIntHandle = use_raw_handle(handle);
102        Self::set_value(temp.clone(), value);
103        temp
104    }
105}
106
107impl<M: ManagedTypeApi> From<BigUint<M>> for BigInt<M> {
108    #[inline]
109    fn from(item: BigUint<M>) -> Self {
110        item.into_big_int()
111    }
112}
113
114macro_rules! big_int_conv_num {
115    ($num_ty:ty) => {
116        impl<M: ManagedTypeApi> From<$num_ty> for BigInt<M> {
117            #[inline]
118            fn from(value: $num_ty) -> Self {
119                unsafe {
120                    let result = BigInt::new_uninit();
121                    Self::set_value(result.get_handle(), value);
122                    result
123                }
124            }
125        }
126
127        impl<M: ManagedTypeApi> TypeAbiFrom<$num_ty> for BigInt<M> {}
128        impl<M: ManagedTypeApi> TypeAbiFrom<&$num_ty> for BigInt<M> {}
129    };
130}
131
132// TODO: more coverage, only from i64 currently tested
133big_int_conv_num! {i64}
134big_int_conv_num! {i32}
135big_int_conv_num! {isize}
136big_int_conv_num! {i16}
137big_int_conv_num! {i8}
138
139#[cfg(feature = "num-bigint")]
140impl<M: ManagedTypeApi> TypeAbiFrom<crate::codec::num_bigint::BigInt> for BigInt<M> {}
141#[cfg(feature = "num-bigint")]
142impl<M: ManagedTypeApi> TypeAbiFrom<BigInt<M>> for crate::codec::num_bigint::BigInt {}
143
144impl<M> TypeAbiFrom<Self> for BigInt<M> where M: ManagedTypeApi {}
145impl<M> TypeAbiFrom<&Self> for BigInt<M> where M: ManagedTypeApi {}
146
147impl<M: ManagedTypeApi> crate::abi::TypeAbi for BigInt<M> {
148    #[cfg(feature = "num-bigint")]
149    type Unmanaged = crate::codec::num_bigint::BigInt;
150
151    #[cfg(not(feature = "num-bigint"))]
152    type Unmanaged = Self;
153
154    fn type_name() -> TypeName {
155        TypeName::from("BigInt")
156    }
157
158    fn type_name_rust() -> TypeName {
159        TypeName::from("BigInt<$API>")
160    }
161}
162
163#[cfg(feature = "num-bigint")]
164impl<M: ManagedTypeApi> From<&crate::codec::num_bigint::BigInt> for BigInt<M> {
165    fn from(alloc_big_int: &crate::codec::num_bigint::BigInt) -> Self {
166        BigInt::from_signed_bytes_be(alloc_big_int.to_signed_bytes_be().as_slice())
167    }
168}
169#[cfg(feature = "num-bigint")]
170impl<M: ManagedTypeApi> From<crate::codec::num_bigint::BigInt> for BigInt<M> {
171    fn from(alloc_big_int: crate::codec::num_bigint::BigInt) -> Self {
172        BigInt::from(&alloc_big_int)
173    }
174}
175
176impl<M: ManagedTypeApi> BigInt<M> {
177    #[inline]
178    pub fn zero() -> Self {
179        unsafe {
180            let result = BigInt::new_uninit();
181            M::managed_type_impl().bi_set_int64(result.get_handle(), 0);
182            result
183        }
184    }
185
186    #[inline]
187    pub fn to_i64(&self) -> Option<i64> {
188        M::managed_type_impl().bi_to_i64(self.handle.clone())
189    }
190
191    #[inline]
192    pub fn overwrite_i64(&self, value: i64) {
193        Self::set_value(self.handle.clone(), value);
194    }
195
196    #[inline]
197    pub fn from_signed_bytes_be(bytes: &[u8]) -> Self {
198        let mb_handle: M::ManagedBufferHandle = use_raw_handle(const_handles::MBUF_TEMPORARY_1);
199        M::managed_type_impl().mb_overwrite(mb_handle.clone(), bytes);
200        unsafe {
201            let result = BigInt::new_uninit();
202            M::managed_type_impl().mb_to_big_int_signed(mb_handle, result.get_handle());
203            result
204        }
205    }
206
207    #[inline]
208    pub fn to_signed_bytes_be(&self) -> BoxedBytes {
209        let mb_handle: M::ManagedBufferHandle = use_raw_handle(const_handles::MBUF_TEMPORARY_1);
210        M::managed_type_impl().mb_from_big_int_signed(self.handle.clone(), mb_handle.clone());
211        M::managed_type_impl().mb_to_boxed_bytes(mb_handle)
212    }
213
214    #[inline]
215    pub fn from_signed_bytes_be_buffer(managed_buffer: &ManagedBuffer<M>) -> Self {
216        unsafe {
217            let result = BigInt::new_uninit();
218            M::managed_type_impl()
219                .mb_to_big_int_signed(managed_buffer.handle.clone(), result.get_handle());
220            result
221        }
222    }
223
224    #[inline]
225    pub fn to_signed_bytes_be_buffer(&self) -> ManagedBuffer<M> {
226        unsafe {
227            let result = ManagedBuffer::new_uninit();
228            M::managed_type_impl().mb_from_big_int_signed(self.handle.clone(), result.get_handle());
229            result
230        }
231    }
232
233    pub(crate) fn clone_to_handle(source_handle: M::BigIntHandle, dest_handle: M::BigIntHandle) {
234        let api = M::managed_type_impl();
235        api.bi_set_int64(dest_handle.clone(), 0);
236        api.bi_add(dest_handle.clone(), dest_handle, source_handle);
237    }
238}
239
240impl<M: ManagedTypeApi> Clone for BigInt<M> {
241    fn clone(&self) -> Self {
242        unsafe {
243            let result = BigInt::new_uninit();
244            BigInt::<M>::clone_to_handle(self.get_handle(), result.get_handle());
245            result
246        }
247    }
248}
249
250impl<M: ManagedTypeApi> BigInt<M> {
251    pub fn from_biguint(sign: Sign, unsigned: BigUint<M>) -> Self {
252        let result = unsigned.into_big_int();
253        if sign.is_minus() {
254            M::managed_type_impl().bi_neg(result.handle.clone(), result.handle.clone());
255        }
256        result
257    }
258
259    /// Returns the sign of the `BigInt` as a `Sign`.
260    pub fn sign(&self) -> Sign {
261        let api = M::managed_type_impl();
262        match api.bi_sign(self.handle.clone()) {
263            crate::api::Sign::Plus => Sign::Plus,
264            crate::api::Sign::NoSign => Sign::NoSign,
265            crate::api::Sign::Minus => Sign::Minus,
266        }
267    }
268
269    /// Returns the magnitude of the `BigInt` as a `BigUint`.
270    pub fn magnitude(&self) -> BigUint<M> {
271        unsafe {
272            let result = BigUint::new_uninit();
273            M::managed_type_impl().bi_abs(result.get_handle(), self.get_handle());
274            result
275        }
276    }
277
278    /// Convert this `BigInt` into its `Sign` and `BigUint` magnitude,
279    /// the reverse of `BigInt::from_biguint`.
280    pub fn to_parts(self) -> (Sign, BigUint<M>) {
281        (self.sign(), self.magnitude())
282    }
283
284    /// Converts to an unsigned `BigUint`, without performing any checks.
285    ///
286    /// # Safety
287    ///
288    /// If the number is negative, undefined behavior might occur further down the execution.
289    pub unsafe fn into_big_uint_unchecked(self) -> BigUint<M> {
290        BigUint { value: self }
291    }
292
293    /// Converts this `BigInt` into a `BigUint`, if it's not negative.
294    pub fn into_big_uint(self) -> ManagedOption<M, BigUint<M>> {
295        if let Sign::Minus = self.sign() {
296            ManagedOption::none()
297        } else {
298            ManagedOption::some(unsafe { self.into_big_uint_unchecked() })
299        }
300    }
301}
302
303impl<M: ManagedTypeApi> TryStaticCast for BigInt<M> {}
304
305impl<M: ManagedTypeApi> TopEncode for BigInt<M> {
306    #[inline]
307    fn top_encode_or_handle_err<O, H>(&self, output: O, h: H) -> Result<(), H::HandledErr>
308    where
309        O: TopEncodeOutput,
310        H: EncodeErrorHandler,
311    {
312        if O::supports_specialized_type::<Self>() {
313            output.set_specialized(self, h)
314        } else {
315            output.set_slice_u8(self.to_signed_bytes_be().as_slice());
316            Ok(())
317        }
318    }
319}
320
321impl<M: ManagedTypeApi> NestedEncode for BigInt<M> {
322    fn dep_encode_or_handle_err<O, H>(&self, dest: &mut O, h: H) -> Result<(), H::HandledErr>
323    where
324        O: NestedEncodeOutput,
325        H: EncodeErrorHandler,
326    {
327        self.to_signed_bytes_be_buffer()
328            .dep_encode_or_handle_err(dest, h)
329    }
330}
331
332impl<M: ManagedTypeApi> NestedDecode for BigInt<M> {
333    fn dep_decode_or_handle_err<I, H>(input: &mut I, h: H) -> Result<Self, H::HandledErr>
334    where
335        I: NestedDecodeInput,
336        H: DecodeErrorHandler,
337    {
338        if I::supports_specialized_type::<Self>() {
339            input.read_specialized((), h)
340        } else {
341            let boxed_bytes = BoxedBytes::dep_decode_or_handle_err(input, h)?;
342            Ok(Self::from_signed_bytes_be(boxed_bytes.as_slice()))
343        }
344    }
345}
346
347impl<M: ManagedTypeApi> TopDecode for BigInt<M> {
348    fn top_decode_or_handle_err<I, H>(input: I, h: H) -> Result<Self, H::HandledErr>
349    where
350        I: TopDecodeInput,
351        H: DecodeErrorHandler,
352    {
353        if I::supports_specialized_type::<Self>() {
354            input.into_specialized(h)
355        } else {
356            let boxed_bytes = BoxedBytes::top_decode_or_handle_err(input, h)?;
357            Ok(Self::from_signed_bytes_be(boxed_bytes.as_slice()))
358        }
359    }
360}
361
362impl<M: ManagedTypeApi> BigInt<M> {
363    #[must_use]
364    pub fn pow(&self, exp: u32) -> Self {
365        let exp_handle = BigUint::<M>::make_temp(const_handles::BIG_INT_TEMPORARY_1, exp);
366        unsafe {
367            let result = BigInt::new_uninit();
368            M::managed_type_impl().bi_pow(result.get_handle(), self.get_handle(), exp_handle);
369            result
370        }
371    }
372}
373
374impl<M: ManagedTypeApi> SCDisplay for BigInt<M> {
375    fn fmt<F: FormatByteReceiver>(&self, f: &mut F) {
376        let str_handle: M::ManagedBufferHandle = use_raw_handle(const_handles::MBUF_TEMPORARY_1);
377        M::managed_type_impl().bi_to_string(self.handle.clone(), str_handle.clone());
378        let cast_handle = str_handle.cast_or_signal_error::<M, _>();
379        let wrap_cast = unsafe { ManagedRef::wrap_handle(cast_handle) };
380        f.append_managed_buffer(&wrap_cast);
381    }
382}
383
384impl<M: ManagedTypeApi> core::fmt::Debug for BigInt<M> {
385    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
386        f.debug_struct("BigInt")
387            .field("handle", &self.handle.clone())
388            .field(
389                "hex-value-be",
390                &encode_bytes_as_hex(self.to_signed_bytes_be().as_slice()),
391            )
392            .finish()
393    }
394}