multiversx_sc/types/managed/basic/
big_int.rs1use 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 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
132big_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 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 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 pub fn to_parts(self) -> (Sign, BigUint<M>) {
281 (self.sign(), self.magnitude())
282 }
283
284 pub unsafe fn into_big_uint_unchecked(self) -> BigUint<M> {
290 BigUint { value: self }
291 }
292
293 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}