multiversx_sc/types/managed/wrapped/
big_uint.rs1use core::convert::TryInto;
2
3use crate::{
4 abi::{TypeAbi, TypeAbiFrom, TypeName},
5 api::{
6 const_handles, use_raw_handle, BigIntApiImpl, HandleConstraints, ManagedBufferApiImpl,
7 ManagedTypeApi, ManagedTypeApiImpl, RawHandle,
8 },
9 codec::{
10 DecodeErrorHandler, EncodeErrorHandler, NestedDecode, NestedDecodeInput, NestedEncode,
11 NestedEncodeOutput, TopDecode, TopDecodeInput, TopEncode, TopEncodeOutput, TryStaticCast,
12 },
13 contract_base::ErrorHelper,
14 formatter::{hex_util::encode_bytes_as_hex, FormatBuffer, FormatByteReceiver, SCDisplay},
15 types::{
16 heap::BoxedBytes, BigInt, Decimals, LnDecimals, ManagedBuffer, ManagedBufferCachedBuilder,
17 ManagedDecimal, ManagedRef, ManagedType,
18 },
19};
20
21#[repr(transparent)]
22pub struct BigUint<M: ManagedTypeApi> {
23 pub(crate) value: BigInt<M>,
24}
25
26impl<M: ManagedTypeApi> ManagedType<M> for BigUint<M> {
27 type OwnHandle = M::BigIntHandle;
28
29 unsafe fn from_handle(handle: M::BigIntHandle) -> Self {
30 BigUint {
31 value: BigInt::from_handle(handle),
32 }
33 }
34
35 fn get_handle(&self) -> M::BigIntHandle {
36 self.value.handle.clone()
37 }
38
39 unsafe fn forget_into_handle(self) -> Self::OwnHandle {
40 self.value.forget_into_handle()
41 }
42
43 fn transmute_from_handle_ref(handle_ref: &M::BigIntHandle) -> &Self {
44 unsafe { core::mem::transmute(handle_ref) }
45 }
46
47 fn transmute_from_handle_ref_mut(handle_ref: &mut M::BigIntHandle) -> &mut Self {
48 unsafe { core::mem::transmute(handle_ref) }
49 }
50}
51
52impl<M: ManagedTypeApi> From<u128> for BigUint<M> {
53 fn from(value: u128) -> Self {
54 BigUint::from_bytes_be(&value.to_be_bytes()[..])
55 }
56}
57
58impl<M: ManagedTypeApi> TypeAbiFrom<u128> for BigUint<M> {}
59
60impl<M: ManagedTypeApi> From<ManagedBuffer<M>> for BigUint<M> {
61 #[inline]
62 fn from(item: ManagedBuffer<M>) -> Self {
63 BigUint::from_bytes_be_buffer(&item)
64 }
65}
66
67impl<M: ManagedTypeApi> From<&ManagedBuffer<M>> for BigUint<M> {
68 #[inline]
69 fn from(item: &ManagedBuffer<M>) -> Self {
70 BigUint::from_bytes_be_buffer(item)
71 }
72}
73
74impl<M: ManagedTypeApi> BigUint<M> {
75 pub unsafe fn new_uninit() -> Self {
81 BigUint {
82 value: BigInt::new_uninit(),
83 }
84 }
85
86 pub(crate) fn set_value<T>(handle: M::BigIntHandle, value: T)
87 where
88 T: TryInto<i64> + num_traits::Unsigned,
89 {
90 BigInt::<M>::set_value(handle, value);
91 }
92
93 pub(crate) fn new_from_num<T>(value: T) -> Self
94 where
95 T: TryInto<i64> + num_traits::Unsigned,
96 {
97 unsafe {
98 let result = Self::new_uninit();
99 Self::set_value(result.get_handle(), value);
100 result
101 }
102 }
103
104 pub(crate) fn make_temp<T>(handle: RawHandle, value: T) -> M::BigIntHandle
105 where
106 T: TryInto<i64> + num_traits::Unsigned,
107 {
108 let temp: M::BigIntHandle = use_raw_handle(handle);
109 Self::set_value(temp.clone(), value);
110 temp
111 }
112
113 pub fn as_big_int(&self) -> &BigInt<M> {
114 &self.value
115 }
116
117 pub fn into_big_int(self) -> BigInt<M> {
118 self.value
119 }
120}
121
122macro_rules! big_uint_conv_num {
123 ($num_ty:ty) => {
124 impl<M: ManagedTypeApi> From<$num_ty> for BigUint<M> {
125 #[inline]
126 fn from(value: $num_ty) -> Self {
127 Self::new_from_num(value)
128 }
129 }
130
131 impl<M: ManagedTypeApi> TypeAbiFrom<$num_ty> for BigUint<M> {}
132 };
133}
134
135big_uint_conv_num! {u64}
136big_uint_conv_num! {u32}
137big_uint_conv_num! {usize}
138big_uint_conv_num! {u16}
139big_uint_conv_num! {u8}
140
141#[cfg(feature = "num-bigint")]
142impl<M: ManagedTypeApi> TypeAbiFrom<crate::codec::num_bigint::BigUint> for BigUint<M> {}
143#[cfg(feature = "num-bigint")]
144impl<M: ManagedTypeApi> TypeAbiFrom<BigUint<M>> for crate::codec::num_bigint::BigUint {}
145
146impl<M> TypeAbiFrom<Self> for BigUint<M> where M: ManagedTypeApi {}
147impl<M> TypeAbiFrom<&Self> for BigUint<M> where M: ManagedTypeApi {}
148
149impl<M: ManagedTypeApi> TypeAbi for BigUint<M> {
150 #[cfg(feature = "num-bigint")]
151 type Unmanaged = crate::codec::num_bigint::BigUint;
152
153 #[cfg(not(feature = "num-bigint"))]
154 type Unmanaged = Self;
155
156 fn type_name() -> TypeName {
157 TypeName::from("BigUint")
158 }
159
160 fn type_name_rust() -> TypeName {
161 TypeName::from("BigUint<$API>")
162 }
163}
164
165#[cfg(feature = "num-bigint")]
166impl<M: ManagedTypeApi> From<&crate::codec::num_bigint::BigUint> for BigUint<M> {
167 fn from(alloc_big_uint: &crate::codec::num_bigint::BigUint) -> Self {
168 BigUint::from_bytes_be(alloc_big_uint.to_bytes_be().as_slice())
169 }
170}
171#[cfg(feature = "num-bigint")]
172impl<M: ManagedTypeApi> From<crate::codec::num_bigint::BigUint> for BigUint<M> {
173 fn from(alloc_big_uint: crate::codec::num_bigint::BigUint) -> Self {
174 BigUint::from(&alloc_big_uint)
175 }
176}
177#[cfg(feature = "num-bigint")]
178impl<M: ManagedTypeApi> BigUint<M> {
179 pub fn to_alloc(&self) -> crate::codec::num_bigint::BigUint {
180 crate::codec::num_bigint::BigUint::from_bytes_be(self.to_bytes_be().as_slice())
181 }
182}
183
184impl<M: ManagedTypeApi> Default for BigUint<M> {
185 #[inline]
186 fn default() -> Self {
187 Self::zero()
188 }
189}
190
191impl<M: ManagedTypeApi> BigUint<M> {
193 #[inline]
194 pub fn zero() -> Self {
195 unsafe {
196 let result = Self::new_uninit();
197 M::managed_type_impl().bi_set_int64(result.get_handle(), 0);
198 result
199 }
200 }
201
202 pub fn zero_ref() -> ManagedRef<'static, M, BigUint<M>> {
203 let handle: M::BigIntHandle = use_raw_handle(const_handles::BIG_INT_CONST_ZERO);
204 M::managed_type_impl().bi_set_int64(handle.clone(), 0);
205 unsafe { ManagedRef::wrap_handle(handle) }
206 }
207
208 #[inline]
209 pub fn to_u64(&self) -> Option<u64> {
210 let api = M::managed_type_impl();
211 api.bi_to_i64(self.value.handle.clone()).map(|bi| bi as u64)
212 }
213
214 #[inline]
215 pub fn overwrite_u64(&mut self, value: u64) {
216 Self::set_value(self.value.handle.clone(), value);
217 }
218
219 pub fn from_bytes_be(bytes: &[u8]) -> Self {
220 let mb_handle: M::ManagedBufferHandle = use_raw_handle(const_handles::MBUF_TEMPORARY_1);
221 M::managed_type_impl().mb_overwrite(mb_handle.clone(), bytes);
222 unsafe {
223 let result = Self::new_uninit();
224 M::managed_type_impl().mb_to_big_int_unsigned(mb_handle, result.get_handle());
225 result
226 }
227 }
228
229 pub fn to_bytes_be(&self) -> BoxedBytes {
230 let mb_handle: M::ManagedBufferHandle = use_raw_handle(const_handles::MBUF_TEMPORARY_1);
231 M::managed_type_impl()
232 .mb_from_big_int_unsigned(self.value.handle.clone(), mb_handle.clone());
233 M::managed_type_impl().mb_to_boxed_bytes(mb_handle)
234 }
235
236 pub fn from_bytes_be_buffer(managed_buffer: &ManagedBuffer<M>) -> Self {
237 unsafe {
238 let result = BigUint::new_uninit();
239 M::managed_type_impl()
240 .mb_to_big_int_unsigned(managed_buffer.handle.clone(), result.get_handle());
241 result
242 }
243 }
244
245 pub fn to_bytes_be_buffer(&self) -> ManagedBuffer<M> {
246 unsafe {
247 let result = ManagedBuffer::new_uninit();
248 M::managed_type_impl().mb_from_big_int_unsigned(self.get_handle(), result.get_handle());
249 result
250 }
251 }
252}
253
254impl<M: ManagedTypeApi> BigUint<M> {
255 pub fn sqrt(&self) -> Self {
256 unsafe {
257 let result = BigUint::new_uninit();
258 M::managed_type_impl().bi_sqrt(result.get_handle(), self.get_handle());
259 result
260 }
261 }
262
263 pub fn pow(&self, exp: u32) -> Self {
264 let big_int_temp_1 = BigUint::<M>::make_temp(const_handles::BIG_INT_TEMPORARY_1, exp);
265 unsafe {
266 let result = BigUint::new_uninit();
267 M::managed_type_impl().bi_pow(result.get_handle(), self.get_handle(), big_int_temp_1);
268 result
269 }
270 }
271
272 pub fn log2_floor(&self) -> Option<u32> {
279 let api = M::managed_type_impl();
280 let result = api.bi_log2(self.value.handle.clone());
281 if result < 0 {
282 None
283 } else {
284 Some(result as u32)
285 }
286 }
287
288 pub fn ln(&self) -> Option<ManagedDecimal<M, LnDecimals>> {
292 let Some(log2_floor) = self.log2_floor() else {
294 return None;
296 };
297
298 let scaling_factor_9 = LnDecimals::new().scaling_factor();
299 let divisor = BigUint::from(1u64) << log2_floor as usize;
300 let normalized = self * &*scaling_factor_9 / divisor;
301
302 let x = normalized
303 .to_u64()
304 .unwrap_or_else(|| ErrorHelper::<M>::signal_error_with_message("ln internal error"))
305 as i64;
306
307 let mut result = crate::types::math_util::logarithm_i64::ln_polynomial(x);
308 crate::types::math_util::logarithm_i64::ln_add_bit_log2(&mut result, log2_floor);
309
310 debug_assert!(result > 0);
311
312 let mut result_bi = normalized; result_bi.overwrite_u64(result as u64);
314
315 Some(ManagedDecimal::const_decimals_from_raw(result_bi))
316 }
317}
318
319impl<M: ManagedTypeApi> Clone for BigUint<M> {
320 fn clone(&self) -> Self {
321 unsafe { self.as_big_int().clone().into_big_uint_unchecked() }
322 }
323}
324
325impl<M: ManagedTypeApi> TryStaticCast for BigUint<M> {}
326
327impl<M: ManagedTypeApi> TopEncode for BigUint<M> {
328 #[inline]
329 fn top_encode_or_handle_err<O, H>(&self, output: O, h: H) -> Result<(), H::HandledErr>
330 where
331 O: TopEncodeOutput,
332 H: EncodeErrorHandler,
333 {
334 if O::supports_specialized_type::<Self>() {
335 output.set_specialized(self, h)
336 } else {
337 output.set_slice_u8(self.to_bytes_be().as_slice());
338 Ok(())
339 }
340 }
341}
342
343impl<M: ManagedTypeApi> NestedEncode for BigUint<M> {
344 fn dep_encode_or_handle_err<O, H>(&self, dest: &mut O, h: H) -> Result<(), H::HandledErr>
345 where
346 O: NestedEncodeOutput,
347 H: EncodeErrorHandler,
348 {
349 self.to_bytes_be_buffer().dep_encode_or_handle_err(dest, h)
350 }
351}
352
353impl<M: ManagedTypeApi> NestedDecode for BigUint<M> {
354 fn dep_decode_or_handle_err<I, H>(input: &mut I, h: H) -> Result<Self, H::HandledErr>
355 where
356 I: NestedDecodeInput,
357 H: DecodeErrorHandler,
358 {
359 if I::supports_specialized_type::<Self>() {
360 input.read_specialized((), h)
361 } else {
362 let boxed_bytes = BoxedBytes::dep_decode_or_handle_err(input, h)?;
363 Ok(Self::from_bytes_be(boxed_bytes.as_slice()))
364 }
365 }
366}
367
368impl<M: ManagedTypeApi> TopDecode for BigUint<M> {
369 fn top_decode_or_handle_err<I, H>(input: I, h: H) -> Result<Self, H::HandledErr>
370 where
371 I: TopDecodeInput,
372 H: DecodeErrorHandler,
373 {
374 if I::supports_specialized_type::<Self>() {
375 input.into_specialized(h)
376 } else {
377 let boxed_bytes = BoxedBytes::top_decode_or_handle_err(input, h)?;
378 Ok(Self::from_bytes_be(boxed_bytes.as_slice()))
379 }
380 }
381}
382
383impl<M: ManagedTypeApi> SCDisplay for BigUint<M> {
384 fn fmt<F: FormatByteReceiver>(&self, f: &mut F) {
385 let str_handle: M::ManagedBufferHandle = use_raw_handle(const_handles::MBUF_TEMPORARY_1);
386 M::managed_type_impl().bi_to_string(self.value.handle.clone(), str_handle.clone());
387 let cast_handle = str_handle.cast_or_signal_error::<M, _>();
388 let wrap_cast = unsafe { ManagedRef::wrap_handle(cast_handle) };
389 f.append_managed_buffer(&wrap_cast);
390 }
391}
392
393impl<M: ManagedTypeApi> BigUint<M> {
394 pub fn to_display(&self) -> ManagedBuffer<M> {
396 let mut result = ManagedBufferCachedBuilder::new_from_slice(&[]);
397 result.append_display(self);
398 result.into_managed_buffer()
399 }
400}
401
402impl<M: ManagedTypeApi> core::fmt::Debug for BigUint<M> {
403 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
404 f.debug_struct("BigUint")
405 .field("handle", &self.value.handle.clone())
406 .field(
407 "hex-value-be",
408 &encode_bytes_as_hex(self.to_bytes_be().as_slice()),
409 )
410 .finish()
411 }
412}