Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

managedVecItem trait impl for ManagedDecimal #1928

Merged
merged 4 commits into from
Jan 20, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 57 additions & 1 deletion framework/base/src/types/managed/wrapped/managed_decimal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,11 @@ use multiversx_sc_codec::{

use core::{cmp::Ordering, ops::Deref};

use super::{ManagedBufferCachedBuilder, ManagedRef};
use super::{
managed_vec_item_read_from_payload_index, managed_vec_item_save_to_payload_index,
ManagedBufferCachedBuilder, ManagedRef, ManagedVecItem, ManagedVecItemPayloadBuffer,
ManagedVecRef,
};

/// Fixed-point decimal numbers that accept either a constant or variable number of decimals.
///
Expand Down Expand Up @@ -136,6 +140,58 @@ impl<M: ManagedTypeApi, const DECIMALS: NumDecimals>
}
}

impl<M: ManagedTypeApi> ManagedVecItem for ManagedDecimal<M, NumDecimals> {
type PAYLOAD = ManagedVecItemPayloadBuffer<8>; // 4 bigUint + 4 usize

const SKIPS_RESERIALIZATION: bool = false;

type Ref<'a> = ManagedVecRef<'a, Self>;

fn read_from_payload(payload: &Self::PAYLOAD) -> Self {
let mut index = 0;
unsafe {
Self {
data: managed_vec_item_read_from_payload_index(payload, &mut index),
decimals: managed_vec_item_read_from_payload_index(payload, &mut index),
}
}
}

unsafe fn borrow_from_payload<'a>(payload: &Self::PAYLOAD) -> Self::Ref<'a> {
ManagedVecRef::new(Self::read_from_payload(payload))
}

fn save_to_payload(self, payload: &mut Self::PAYLOAD) {
let mut index = 0;
unsafe {
managed_vec_item_save_to_payload_index(self.data, payload, &mut index);
managed_vec_item_save_to_payload_index(self.decimals, payload, &mut index);
}
}
}

impl<M: ManagedTypeApi, const N: NumDecimals> ManagedVecItem
for ManagedDecimal<M, ConstDecimals<N>>
{
type PAYLOAD = ManagedVecItemPayloadBuffer<4>; // data only

const SKIPS_RESERIALIZATION: bool = false;

type Ref<'a> = ManagedVecRef<'a, Self>;

fn read_from_payload(payload: &Self::PAYLOAD) -> Self {
Self::const_decimals_from_raw(BigUint::read_from_payload(payload))
}

unsafe fn borrow_from_payload<'a>(payload: &Self::PAYLOAD) -> Self::Ref<'a> {
ManagedVecRef::new(Self::read_from_payload(payload))
}

fn save_to_payload(self, payload: &mut Self::PAYLOAD) {
self.data.save_to_payload(payload);
}
}

impl<M: ManagedTypeApi, const DECIMALS: NumDecimals> TopEncode
for ManagedDecimal<M, ConstDecimals<DECIMALS>>
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ use crate::{
},
err_msg,
formatter::{FormatBuffer, FormatByteReceiver, SCDisplay},
types::{BigFloat, BigInt, BigUint, Sign},
types::{
managed_vec_item_read_from_payload_index, managed_vec_item_save_to_payload_index, BigFloat,
BigInt, BigUint, ManagedVecItem, ManagedVecItemPayloadBuffer, ManagedVecRef, Sign,
},
};

use alloc::string::ToString;
Expand Down Expand Up @@ -187,6 +190,58 @@ impl<M: ManagedTypeApi, const DECIMALS: NumDecimals> From<f32>
}
}

impl<M: ManagedTypeApi> ManagedVecItem for ManagedDecimalSigned<M, NumDecimals> {
type PAYLOAD = ManagedVecItemPayloadBuffer<8>; // 4 bigInt + 4 usize

const SKIPS_RESERIALIZATION: bool = false;

type Ref<'a> = ManagedVecRef<'a, Self>;

fn read_from_payload(payload: &Self::PAYLOAD) -> Self {
let mut index = 0;
unsafe {
Self {
data: managed_vec_item_read_from_payload_index(payload, &mut index),
decimals: managed_vec_item_read_from_payload_index(payload, &mut index),
}
}
}

unsafe fn borrow_from_payload<'a>(payload: &Self::PAYLOAD) -> Self::Ref<'a> {
ManagedVecRef::new(Self::read_from_payload(payload))
}

fn save_to_payload(self, payload: &mut Self::PAYLOAD) {
let mut index = 0;
unsafe {
managed_vec_item_save_to_payload_index(self.data, payload, &mut index);
managed_vec_item_save_to_payload_index(self.decimals, payload, &mut index);
}
}
}

impl<M: ManagedTypeApi, const N: NumDecimals> ManagedVecItem
for ManagedDecimalSigned<M, ConstDecimals<N>>
{
type PAYLOAD = ManagedVecItemPayloadBuffer<4>; // data only

const SKIPS_RESERIALIZATION: bool = false;

type Ref<'a> = ManagedVecRef<'a, Self>;

fn read_from_payload(payload: &Self::PAYLOAD) -> Self {
Self::const_decimals_from_raw(BigInt::read_from_payload(payload))
}

unsafe fn borrow_from_payload<'a>(payload: &Self::PAYLOAD) -> Self::Ref<'a> {
ManagedVecRef::new(Self::read_from_payload(payload))
}

fn save_to_payload(self, payload: &mut Self::PAYLOAD) {
self.data.save_to_payload(payload);
}
}

impl<M: ManagedTypeApi, const DECIMALS: NumDecimals> TopEncode
for ManagedDecimalSigned<M, ConstDecimals<DECIMALS>>
{
Expand Down
70 changes: 70 additions & 0 deletions framework/scenario/tests/derive_managed_vec_item_decimal_test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
use multiversx_sc::{
api::ManagedTypeApi,
codec::{
self,
derive::{NestedDecode, NestedEncode, TopDecode, TopEncode},
},
derive::ManagedVecItem,
types::{
BigInt, BigUint, ConstDecimals, ManagedDecimal, ManagedDecimalSigned,
ManagedVecItemPayload, NumDecimals,
},
};
use multiversx_sc_scenario::api::StaticApi;

// to test, run the following command in the crate folder:
// cargo expand --test derive_managed_vec_item_biguint_test > expanded.rs

#[derive(
ManagedVecItem, NestedEncode, NestedDecode, TopEncode, TopDecode, PartialEq, Clone, Debug,
)]
pub struct ManagedStructWithDecimal<M: ManagedTypeApi> {
pub var_dec: ManagedDecimal<M, NumDecimals>,
pub const_dec: ManagedDecimal<M, ConstDecimals<4>>,
pub var_dec_signed: ManagedDecimalSigned<M, NumDecimals>,
pub const_dec_signed: ManagedDecimalSigned<M, ConstDecimals<4>>,
}

#[test]
#[allow(clippy::assertions_on_constants)]
fn struct_with_decimal_static() {
assert_eq!(
<ManagedStructWithDecimal<StaticApi> as multiversx_sc::types::ManagedVecItem>::payload_size(
),
24
);
assert!(
!<ManagedStructWithDecimal<StaticApi> as multiversx_sc::types::ManagedVecItem>::SKIPS_RESERIALIZATION
);
}

#[test]
fn struct_with_decimal_read_write() {
let num_dec_1 = 3;
let num_dec_2 = 5;
let s = ManagedStructWithDecimal::<StaticApi> {
var_dec: ManagedDecimal::from_raw_units(BigUint::from(123_000u32), num_dec_1),
const_dec: ManagedDecimal::from_raw_units(BigUint::from(124_000u32), ConstDecimals),
var_dec_signed: ManagedDecimalSigned::from_raw_units(BigInt::from(125_000), num_dec_2),
const_dec_signed: ManagedDecimalSigned::from_raw_units(
BigInt::from(-126_000),
ConstDecimals,
),
};

let mut payload = <ManagedStructWithDecimal<StaticApi> as multiversx_sc::types::ManagedVecItem>::PAYLOAD::new_buffer();
<ManagedStructWithDecimal<StaticApi> as multiversx_sc::types::ManagedVecItem>::save_to_payload(
s.clone(),
&mut payload,
);
let struct_from_bytes =
<ManagedStructWithDecimal<StaticApi> as multiversx_sc::types::ManagedVecItem>::read_from_payload(
&payload
);
assert_eq!(struct_from_bytes, s);

// check payload
let slice = payload.payload_slice();
assert_eq!(slice[7], num_dec_1 as u8);
assert_eq!(slice[19], num_dec_2 as u8);
}
2 changes: 1 addition & 1 deletion framework/snippets/src/multi/homogenous_tx_buffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ where
}
}

impl<'w, GatewayProxy, Step, RH> HomogenousTxBuffer<'w, GatewayProxy, Step, RH>
impl<GatewayProxy, Step, RH> HomogenousTxBuffer<'_, GatewayProxy, Step, RH>
where
GatewayProxy: GatewayAsyncService,
Step: InteractorStep,
Expand Down
2 changes: 1 addition & 1 deletion sdk/core/src/crypto/edwards25519/constant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use super::{field_element::FieldElement, pre_computed_group_element::PreComputed

// base contains precomputed multiples of the base-point. See the Ed25519 paper
// for a discussion about how these values are used.
pub const BASE: [[PreComputedGroupElement; 8]; 32] = [
pub static BASE: [[PreComputedGroupElement; 8]; 32] = [
[
PreComputedGroupElement {
y_plus_x: FieldElement([
Expand Down
2 changes: 1 addition & 1 deletion sdk/scenario-format/src/value_interpreter/file_loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ fn missing_file_value(path_buf: &Path) -> Vec<u8> {
///
/// Source: https://stackoverflow.com/questions/68231306/stdfscanonicalize-for-files-that-dont-exist
fn normalize_path<P: AsRef<Path>>(path: P) -> PathBuf {
let ends_with_slash = path.as_ref().to_str().map_or(false, |s| s.ends_with('/'));
let ends_with_slash = path.as_ref().to_str().is_some_and(|s| s.ends_with('/'));
let mut normalized = PathBuf::new();
for component in path.as_ref().components() {
match &component {
Expand Down
Loading