Skip to content

Commit

Permalink
EgldOrEsdtTokenIdentifier/TokenIdentifier refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
andrei-marinica committed Dec 5, 2024
1 parent 0f19b6a commit 56f2dc5
Show file tree
Hide file tree
Showing 4 changed files with 166 additions and 67 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,10 @@ use crate::{
BigUint, ConstDecimals, EgldOrEsdtTokenIdentifier, EgldOrEsdtTokenPayment,
EgldOrMultiEsdtPayment, EsdtTokenPayment, ManagedDecimal, ManagedRef, ManagedType,
ManagedVec, ManagedVecItem, ManagedVecItemPayload, ManagedVecPayloadIterator,
ManagedVecRef, TokenIdentifier,
ManagedVecRef, TokenIdentifier, EGLD_000000_TOKEN_IDENTIFIER,
},
};

const EGLD_000000_TOKEN_IDENTIFIER: &str = "EGLD-000000";

#[derive(Default)]
pub struct CallValueWrapper<A>
where
Expand Down
2 changes: 1 addition & 1 deletion framework/base/src/types/managed/wrapped.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ mod traits;

pub use big_uint::BigUint;
pub use builder::*;
pub use egld_or_esdt_token_identifier::EgldOrEsdtTokenIdentifier;
pub use egld_or_esdt_token_identifier::{EgldOrEsdtTokenIdentifier, EGLD_000000_TOKEN_IDENTIFIER};
pub use egld_or_esdt_token_payment::{EgldOrEsdtTokenPayment, EgldOrEsdtTokenPaymentRefs};
pub use egld_or_multi_esdt_payment::{EgldOrMultiEsdtPayment, EgldOrMultiEsdtPaymentRefs};
pub(crate) use encoded_managed_vec_item::EncodedManagedVecItem;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,21 @@ use alloc::string::ToString;

use crate::{
abi::{TypeAbi, TypeAbiFrom, TypeName},
api::{HandleConstraints, ManagedTypeApi},
api::{
const_handles, use_raw_handle, ErrorApiImpl, HandleConstraints, ManagedBufferApiImpl,
ManagedTypeApi,
},
codec::*,
derive::ManagedVecItem,
formatter::{FormatByteReceiver, SCDisplay, SCLowerHex},
proxy_imports::TestTokenIdentifier,
types::{ManagedBuffer, ManagedOption, ManagedRef, ManagedType, TokenIdentifier},
types::{ManagedBuffer, ManagedRef, ManagedType, TokenIdentifier},
};

use crate as multiversx_sc; // required by the ManagedVecItem derive

pub const EGLD_000000_TOKEN_IDENTIFIER: &str = "EGLD-000000";

/// Specialized type for handling either EGLD or ESDT token identifiers.
///
/// Equivalent to a structure of the form
Expand All @@ -30,19 +35,45 @@ use crate as multiversx_sc; // required by the ManagedVecItem derive
#[repr(transparent)]
#[derive(ManagedVecItem, Clone)]
pub struct EgldOrEsdtTokenIdentifier<M: ManagedTypeApi> {
pub(crate) data: ManagedOption<M, TokenIdentifier<M>>,
pub(crate) buffer: ManagedBuffer<M>,
}

impl<M: ManagedTypeApi> ManagedType<M> for EgldOrEsdtTokenIdentifier<M> {
type OwnHandle = M::ManagedBufferHandle;

#[inline]
unsafe fn from_handle(handle: M::ManagedBufferHandle) -> Self {
EgldOrEsdtTokenIdentifier {
buffer: ManagedBuffer::from_handle(handle),
}
}

fn get_handle(&self) -> M::ManagedBufferHandle {
self.buffer.get_handle()
}

unsafe fn forget_into_handle(self) -> Self::OwnHandle {
self.buffer.forget_into_handle()
}

fn transmute_from_handle_ref(handle_ref: &M::ManagedBufferHandle) -> &Self {
unsafe { core::mem::transmute(handle_ref) }
}

fn transmute_from_handle_ref_mut(handle_ref: &mut M::ManagedBufferHandle) -> &mut Self {
unsafe { core::mem::transmute(handle_ref) }
}
}

impl<M: ManagedTypeApi> EgldOrEsdtTokenIdentifier<M> {
/// This special representation is interpreted as the EGLD token.
#[allow(clippy::needless_borrow)] // clippy is wrog here, there is no other way
pub const EGLD_REPRESENTATION: &'static [u8; 4] = &b"EGLD";
pub const EGLD_REPRESENTATION: &'static [u8; 4] = b"EGLD";

/// New instance of the special EGLD token representation.
#[inline]
pub fn egld() -> Self {
Self {
data: ManagedOption::none(),
EgldOrEsdtTokenIdentifier {
buffer: ManagedBuffer::from(EGLD_000000_TOKEN_IDENTIFIER),
}
}

Expand All @@ -52,30 +83,36 @@ impl<M: ManagedTypeApi> EgldOrEsdtTokenIdentifier<M> {
where
TokenIdentifier<M>: From<TI>,
{
Self {
data: ManagedOption::some(TokenIdentifier::from(token_identifier)),
}
let ti_obj = TokenIdentifier::from(token_identifier);
ti_obj.data
}

pub fn parse(data: ManagedBuffer<M>) -> Self {
if data == Self::EGLD_REPRESENTATION {
Self::egld()
} else {
Self::esdt(TokenIdentifier::from(data))
Self { buffer: data }
}
}

#[inline]
pub fn is_egld(&self) -> bool {
self.data.is_none()
M::managed_type_impl().mb_overwrite(
use_raw_handle(const_handles::MBUF_EGLD_000000),
EGLD_000000_TOKEN_IDENTIFIER.as_bytes(),
);
M::managed_type_impl().mb_eq(
use_raw_handle(const_handles::MBUF_EGLD_000000),
self.buffer.handle.clone(),
)
}

#[inline]
pub fn is_esdt(&self) -> bool {
self.data.is_some()
!self.is_egld()
}

#[inline]
/// Returns "EGLD" or the token identifier.
pub fn into_name(self) -> ManagedBuffer<M> {
self.map_or_else(
(),
Expand All @@ -95,43 +132,97 @@ impl<M: ManagedTypeApi> EgldOrEsdtTokenIdentifier<M> {
)
}

#[inline]
pub fn into_managed_buffer(self) -> ManagedBuffer<M> {
self.buffer
}

#[inline]
pub fn as_managed_buffer(&self) -> &ManagedBuffer<M> {
&self.buffer
}

#[inline]
pub fn to_boxed_bytes(&self) -> crate::types::heap::BoxedBytes {
self.buffer.to_boxed_bytes()
}

pub fn map_or_else<Context, D, F, R>(self, context: Context, for_egld: D, for_esdt: F) -> R
where
D: FnOnce(Context) -> R,
F: FnOnce(Context, TokenIdentifier<M>) -> R,
{
self.data.map_or_else(context, for_egld, for_esdt)
if self.is_egld() {
for_egld(context)
} else {
unsafe { for_esdt(context, TokenIdentifier::esdt_unchecked(self)) }
}
}

pub fn map_ref_or_else<Context, D, F, R>(&self, context: Context, for_egld: D, for_esdt: F) -> R
where
D: FnOnce(Context) -> R,
F: FnOnce(Context, &TokenIdentifier<M>) -> R,
{
self.data.map_ref_or_else(context, for_egld, for_esdt)
if self.is_egld() {
for_egld(context)
} else {
unsafe {
let token_identifier =
ManagedRef::<'_, M, TokenIdentifier<M>>::wrap_handle(self.get_handle());
for_esdt(context, &token_identifier)
}
}
}

pub fn unwrap_esdt(self) -> TokenIdentifier<M> {
self.data.unwrap_or_sc_panic("ESDT expected")
self.map_or_else(
(),
|()| M::error_api_impl().signal_error(b"ESDT expected"),
|(), token_identifier| token_identifier,
)
}

/// Representation of the object as an `Option`.
///
/// Because it does not consume `self` only a reference to the ESDT token identifier can be returned.
pub fn as_esdt_option(&self) -> Option<ManagedRef<'_, M, TokenIdentifier<M>>> {
self.data.as_option()
if self.is_egld() {
None
} else {
unsafe {
Some(ManagedRef::<'_, M, TokenIdentifier<M>>::wrap_handle(
self.get_handle(),
))
}
}
}

/// Converts `self` into an `Option`. Consumes `self` in the process.
pub fn into_esdt_option(self) -> Option<TokenIdentifier<M>> {
self.data.into_option()
self.map_or_else((), |()| None, |(), token_identifier| Some(token_identifier))
}
}

impl<M: ManagedTypeApi> From<ManagedBuffer<M>> for EgldOrEsdtTokenIdentifier<M> {
#[inline]
fn from(buffer: ManagedBuffer<M>) -> Self {
EgldOrEsdtTokenIdentifier { buffer }
}
}

impl<M: ManagedTypeApi> From<&[u8]> for EgldOrEsdtTokenIdentifier<M> {
fn from(bytes: &[u8]) -> Self {
EgldOrEsdtTokenIdentifier {
buffer: ManagedBuffer::new_from_bytes(bytes),
}
}
}

impl<M: ManagedTypeApi> PartialEq for EgldOrEsdtTokenIdentifier<M> {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.data == other.data
self.buffer == other.buffer
}
}

Expand All @@ -155,10 +246,10 @@ impl<M: ManagedTypeApi> NestedEncode for EgldOrEsdtTokenIdentifier<M> {
O: NestedEncodeOutput,
H: EncodeErrorHandler,
{
if let Some(token_identifier) = self.data.as_option() {
token_identifier.dep_encode_or_handle_err(dest, h)
} else {
if self.is_egld() {
(&Self::EGLD_REPRESENTATION[..]).dep_encode_or_handle_err(dest, h)
} else {
self.buffer.dep_encode_or_handle_err(dest, h)
}
}
}
Expand All @@ -170,10 +261,10 @@ impl<M: ManagedTypeApi> TopEncode for EgldOrEsdtTokenIdentifier<M> {
O: TopEncodeOutput,
H: EncodeErrorHandler,
{
if let Some(token_identifier) = self.data.as_option() {
token_identifier.top_encode_or_handle_err(output, h)
} else {
if self.is_egld() {
(&Self::EGLD_REPRESENTATION[..]).top_encode_or_handle_err(output, h)
} else {
self.buffer.top_encode_or_handle_err(output, h)
}
}
}
Expand Down Expand Up @@ -231,12 +322,12 @@ impl<M: ManagedTypeApi> TypeAbi for EgldOrEsdtTokenIdentifier<M> {

impl<M: ManagedTypeApi> SCDisplay for EgldOrEsdtTokenIdentifier<M> {
fn fmt<F: FormatByteReceiver>(&self, f: &mut F) {
if let Some(token_identifier) = self.data.as_option() {
let cast_handle = token_identifier.get_handle().cast_or_signal_error::<M, _>();
if self.is_egld() {
f.append_bytes(Self::EGLD_REPRESENTATION);
} else {
let cast_handle = self.buffer.get_handle().cast_or_signal_error::<M, _>();
let wrap_cast = unsafe { ManagedRef::wrap_handle(cast_handle) };
f.append_managed_buffer(&wrap_cast);
} else {
f.append_bytes(Self::EGLD_REPRESENTATION);
}
}
}
Expand All @@ -245,12 +336,12 @@ const EGLD_REPRESENTATION_HEX: &[u8] = b"45474C44";

impl<M: ManagedTypeApi> SCLowerHex for EgldOrEsdtTokenIdentifier<M> {
fn fmt<F: FormatByteReceiver>(&self, f: &mut F) {
if let Some(token_identifier) = self.data.as_option() {
let cast_handle = token_identifier.get_handle().cast_or_signal_error::<M, _>();
if self.is_egld() {
f.append_bytes(EGLD_REPRESENTATION_HEX);
} else {
let cast_handle = self.buffer.get_handle().cast_or_signal_error::<M, _>();
let wrap_cast = unsafe { ManagedRef::wrap_handle(cast_handle) };
f.append_managed_buffer_lower_hex(&wrap_cast);
} else {
f.append_bytes(EGLD_REPRESENTATION_HEX);
}
}
}
Expand Down
Loading

0 comments on commit 56f2dc5

Please sign in to comment.