use core::convert::TryInto;
use crate::{
abi::TypeName,
api::{
const_handles, use_raw_handle, BigIntApi, HandleConstraints, ManagedBufferApi,
ManagedTypeApi, ManagedTypeApiImpl, RawHandle, StaticVarApiImpl,
},
formatter::{hex_util::encode_bytes_as_hex, FormatByteReceiver, SCDisplay},
types::{heap::BoxedBytes, ManagedBuffer, ManagedType},
};
use elrond_codec::{
CodecFrom, CodecFromSelf, DecodeErrorHandler, EncodeErrorHandler, NestedDecode,
NestedDecodeInput, NestedEncode, NestedEncodeOutput, TopDecode, TopDecodeInput, TopEncode,
TopEncodeOutput, TryStaticCast,
};
use super::cast_to_i64::cast_to_i64;
#[repr(transparent)]
pub struct BigUint<M: ManagedTypeApi> {
pub(crate) handle: M::BigIntHandle,
}
impl<M: ManagedTypeApi> ManagedType<M> for BigUint<M> {
type OwnHandle = M::BigIntHandle;
fn from_handle(handle: M::BigIntHandle) -> Self {
BigUint { handle }
}
fn get_handle(&self) -> M::BigIntHandle {
self.handle.clone()
}
fn transmute_from_handle_ref(handle_ref: &M::BigIntHandle) -> &Self {
unsafe { core::mem::transmute(handle_ref) }
}
}
impl<M: ManagedTypeApi> From<ManagedBuffer<M>> for BigUint<M> {
#[inline]
fn from(item: ManagedBuffer<M>) -> Self {
BigUint::from_bytes_be_buffer(&item)
}
}
impl<M: ManagedTypeApi> From<&ManagedBuffer<M>> for BigUint<M> {
#[inline]
fn from(item: &ManagedBuffer<M>) -> Self {
BigUint::from_bytes_be_buffer(item)
}
}
impl<M: ManagedTypeApi> BigUint<M> {
pub(crate) fn set_value<T>(handle: M::BigIntHandle, value: T)
where
T: TryInto<i64> + num_traits::Unsigned,
{
M::managed_type_impl().bi_set_int64(handle, cast_to_i64::<M, _>(value));
}
pub(crate) fn make_temp<T>(handle: RawHandle, value: T) -> M::BigIntHandle
where
T: TryInto<i64> + num_traits::Unsigned,
{
let temp: M::BigIntHandle = use_raw_handle(handle);
Self::set_value(temp.clone(), value);
temp
}
}
macro_rules! big_uint_conv_num {
($num_ty:ty) => {
impl<M: ManagedTypeApi> From<$num_ty> for BigUint<M> {
#[inline]
fn from(value: $num_ty) -> Self {
let handle: M::BigIntHandle = M::static_var_api_impl().next_handle();
Self::set_value(handle.clone(), value);
BigUint::from_handle(handle)
}
}
impl<M: ManagedTypeApi> CodecFrom<$num_ty> for BigUint<M> {}
};
}
big_uint_conv_num! {u64}
big_uint_conv_num! {u32}
big_uint_conv_num! {usize}
big_uint_conv_num! {u16}
big_uint_conv_num! {u8}
impl<M> CodecFromSelf for BigUint<M> where M: ManagedTypeApi {}
#[cfg(feature = "num-bigint")]
impl<M: ManagedTypeApi> CodecFrom<elrond_codec::num_bigint::BigUint> for BigUint<M> {}
#[cfg(feature = "num-bigint")]
impl<M: ManagedTypeApi> CodecFrom<BigUint<M>> for elrond_codec::num_bigint::BigUint {}
#[cfg(feature = "num-bigint")]
impl<M: ManagedTypeApi> From<&elrond_codec::num_bigint::BigUint> for BigUint<M> {
fn from(alloc_big_uint: &elrond_codec::num_bigint::BigUint) -> Self {
BigUint::from_bytes_be(alloc_big_uint.to_bytes_be().as_slice())
}
}
#[cfg(feature = "num-bigint")]
impl<M: ManagedTypeApi> From<elrond_codec::num_bigint::BigUint> for BigUint<M> {
fn from(alloc_big_uint: elrond_codec::num_bigint::BigUint) -> Self {
BigUint::from(&alloc_big_uint)
}
}
#[cfg(feature = "num-bigint")]
impl<M: ManagedTypeApi> BigUint<M> {
pub fn to_alloc(&self) -> elrond_codec::num_bigint::BigUint {
elrond_codec::num_bigint::BigUint::from_bytes_be(self.to_bytes_be().as_slice())
}
}
impl<M: ManagedTypeApi> Default for BigUint<M> {
#[inline]
fn default() -> Self {
Self::zero()
}
}
impl<M: ManagedTypeApi> BigUint<M> {
#[inline]
pub fn zero() -> Self {
let handle: M::BigIntHandle = M::static_var_api_impl().next_handle();
M::managed_type_impl().bi_set_int64(handle.clone(), 0);
BigUint::from_handle(handle)
}
#[inline]
pub fn to_u64(&self) -> Option<u64> {
let api = M::managed_type_impl();
api.bi_to_i64(self.handle.clone()).map(|bi| bi as u64)
}
#[inline]
pub fn overwrite_u64(&self, value: u64) {
Self::set_value(self.handle.clone(), value);
}
#[inline]
pub fn from_bytes_be(bytes: &[u8]) -> Self {
let api = M::managed_type_impl();
let result_handle: M::BigIntHandle = M::static_var_api_impl().next_handle();
api.bi_set_unsigned_bytes(result_handle.clone(), bytes);
BigUint::from_handle(result_handle)
}
#[inline]
pub fn to_bytes_be(&self) -> BoxedBytes {
let api = M::managed_type_impl();
api.bi_get_unsigned_bytes(self.handle.clone())
}
#[inline]
pub fn from_bytes_be_buffer(managed_buffer: &ManagedBuffer<M>) -> Self {
let handle: M::BigIntHandle = M::static_var_api_impl().next_handle();
M::managed_type_impl()
.mb_to_big_int_unsigned(managed_buffer.handle.clone(), handle.clone());
BigUint::from_handle(handle)
}
#[inline]
pub fn to_bytes_be_buffer(&self) -> ManagedBuffer<M> {
let mb_handle: M::ManagedBufferHandle = M::static_var_api_impl().next_handle();
M::managed_type_impl().mb_from_big_int_unsigned(self.handle.clone(), mb_handle.clone());
ManagedBuffer::from_handle(mb_handle)
}
pub fn copy_to_array_big_endian_pad_right(&self, target: &mut [u8; 32]) {
let api = M::managed_type_impl();
let mbuf_temp_1: M::ManagedBufferHandle = use_raw_handle(const_handles::MBUF_TEMPORARY_1);
api.mb_from_big_int_unsigned(self.handle.clone(), mbuf_temp_1.clone());
api.mb_copy_to_slice_pad_right(mbuf_temp_1, &mut target[..]);
}
}
impl<M: ManagedTypeApi> BigUint<M> {
#[inline]
#[must_use]
pub fn sqrt(&self) -> Self {
let api = M::managed_type_impl();
let result_handle: M::BigIntHandle = M::static_var_api_impl().next_handle();
api.bi_sqrt(result_handle.clone(), self.handle.clone());
BigUint::from_handle(result_handle)
}
#[must_use]
pub fn pow(&self, exp: u32) -> Self {
let result_handle: M::BigIntHandle = M::static_var_api_impl().next_handle();
let big_int_temp_1 = BigUint::<M>::make_temp(const_handles::BIG_INT_TEMPORARY_1, exp);
M::managed_type_impl().bi_pow(result_handle.clone(), self.handle.clone(), big_int_temp_1);
BigUint::from_handle(result_handle)
}
#[inline]
pub fn log2(&self) -> u32 {
let api = M::managed_type_impl();
api.bi_log2(self.handle.clone())
}
}
impl<M: ManagedTypeApi> Clone for BigUint<M> {
fn clone(&self) -> Self {
let api = M::managed_type_impl();
let clone_handle: M::BigIntHandle = M::static_var_api_impl().next_handle();
api.bi_set_int64(clone_handle.clone(), 0);
api.bi_add(
clone_handle.clone(),
clone_handle.clone(),
self.handle.clone(),
);
BigUint::from_handle(clone_handle)
}
}
impl<M: ManagedTypeApi> TryStaticCast for BigUint<M> {}
impl<M: ManagedTypeApi> TopEncode for BigUint<M> {
#[inline]
fn top_encode_or_handle_err<O, H>(&self, output: O, h: H) -> Result<(), H::HandledErr>
where
O: TopEncodeOutput,
H: EncodeErrorHandler,
{
if O::supports_specialized_type::<Self>() {
output.set_specialized(self, h)
} else {
output.set_slice_u8(self.to_bytes_be().as_slice());
Ok(())
}
}
}
impl<M: ManagedTypeApi> NestedEncode for BigUint<M> {
fn dep_encode_or_handle_err<O, H>(&self, dest: &mut O, h: H) -> Result<(), H::HandledErr>
where
O: NestedEncodeOutput,
H: EncodeErrorHandler,
{
self.to_bytes_be_buffer().dep_encode_or_handle_err(dest, h)
}
}
impl<M: ManagedTypeApi> NestedDecode for BigUint<M> {
fn dep_decode_or_handle_err<I, H>(input: &mut I, h: H) -> Result<Self, H::HandledErr>
where
I: NestedDecodeInput,
H: DecodeErrorHandler,
{
if I::supports_specialized_type::<Self>() {
input.read_specialized((), h)
} else {
let boxed_bytes = BoxedBytes::dep_decode_or_handle_err(input, h)?;
Ok(Self::from_bytes_be(boxed_bytes.as_slice()))
}
}
}
impl<M: ManagedTypeApi> TopDecode for BigUint<M> {
fn top_decode_or_handle_err<I, H>(input: I, h: H) -> Result<Self, H::HandledErr>
where
I: TopDecodeInput,
H: DecodeErrorHandler,
{
if I::supports_specialized_type::<Self>() {
input.into_specialized(h)
} else {
let boxed_bytes = BoxedBytes::top_decode_or_handle_err(input, h)?;
Ok(Self::from_bytes_be(boxed_bytes.as_slice()))
}
}
}
impl<M: ManagedTypeApi> crate::abi::TypeAbi for BigUint<M> {
fn type_name() -> TypeName {
TypeName::from("BigUint")
}
}
impl<M: ManagedTypeApi> SCDisplay for BigUint<M> {
fn fmt<F: FormatByteReceiver>(&self, f: &mut F) {
let str_handle: M::ManagedBufferHandle = use_raw_handle(const_handles::MBUF_TEMPORARY_1);
M::managed_type_impl().bi_to_string(self.handle.clone(), str_handle.clone());
f.append_managed_buffer(&ManagedBuffer::from_handle(
str_handle.cast_or_signal_error::<M, _>(),
));
}
}
impl<M: ManagedTypeApi> core::fmt::Debug for BigUint<M> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("BigUint")
.field("handle", &self.handle.clone())
.field(
"hex-value-be",
&encode_bytes_as_hex(self.to_bytes_be().as_slice()),
)
.finish()
}
}