Skip to content

Commit cd4d252

Browse files
Merge pull request #1931 from multiversx/managemap-encoded
ManagedMapEncoded - new impl
2 parents 00d5101 + c4c7496 commit cd4d252

File tree

3 files changed

+331
-0
lines changed

3 files changed

+331
-0
lines changed

framework/base/src/types/managed/wrapped.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ mod managed_address;
1212
mod managed_buffer_read_to_end;
1313
mod managed_byte_array;
1414
mod managed_decimal;
15+
mod managed_map_encoded;
1516
mod managed_option;
1617
mod managed_ref;
1718
mod managed_ref_mut;
@@ -46,6 +47,7 @@ pub use managed_byte_array::ManagedByteArray;
4647
pub use managed_decimal::{
4748
ConstDecimals, Decimals, ManagedDecimal, ManagedDecimalSigned, NumDecimals,
4849
};
50+
pub use managed_map_encoded::ManagedMapEncoded;
4951
pub use managed_option::ManagedOption;
5052
pub use managed_ref::ManagedRef;
5153
pub use managed_ref_mut::ManagedRefMut;
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
use multiversx_sc_codec::{TopDecode, TopEncode};
2+
use unwrap_infallible::UnwrapInfallible;
3+
4+
use crate::api::{const_handles, ErrorApi, ManagedTypeApi};
5+
use crate::contract_base::ExitCodecErrorHandler;
6+
use crate::err_msg;
7+
use crate::types::{ManagedBuffer, ManagedMap, ManagedRefMut};
8+
use core::marker::PhantomData;
9+
10+
/// A managed map that works with any serializable key and value types.
11+
///
12+
/// It encodes both when saving, and decodes the value when getting.
13+
///
14+
/// ## Empty encodings
15+
///
16+
/// Just like the base ManagedMap, it makes no difference between a missing key
17+
/// and a key with a corresponding empty encoded value.
18+
///
19+
/// So, for instance, here `contains` returns false, because `0` is encoded as an empty buffer:
20+
///
21+
/// ```no_run
22+
/// # let mut mme = multiversx_sc::types::ManagedMapEncoded::<multiversx_sc::api::uncallable::UncallableApi, i32, i32>::new();
23+
/// # let key = 1;
24+
/// mme.put(&key, &0);
25+
/// assert!(!mme.contains(&key));
26+
/// ```
27+
#[derive(Default)]
28+
pub struct ManagedMapEncoded<M, K, V>
29+
where
30+
M: ManagedTypeApi,
31+
{
32+
pub(super) raw_map: ManagedMap<M>,
33+
_phantom: PhantomData<(K, V)>,
34+
}
35+
36+
impl<M, K, V> ManagedMapEncoded<M, K, V>
37+
where
38+
M: ManagedTypeApi,
39+
{
40+
#[inline]
41+
fn from_raw_map(raw_map: ManagedMap<M>) -> Self {
42+
ManagedMapEncoded {
43+
raw_map,
44+
_phantom: PhantomData,
45+
}
46+
}
47+
48+
pub fn new() -> Self {
49+
ManagedMapEncoded::from_raw_map(ManagedMap::new())
50+
}
51+
}
52+
53+
impl<M, K, V> ManagedMapEncoded<M, K, V>
54+
where
55+
M: ManagedTypeApi + ErrorApi,
56+
K: TopEncode,
57+
V: TopEncode + TopDecode,
58+
{
59+
/// Retrieves and decodes value associated with key.
60+
pub fn get(&self, key: &K) -> V {
61+
let temp_key = temp_key_encode(key);
62+
let value_raw = self.raw_map.get(&temp_key);
63+
value_decode(value_raw)
64+
}
65+
66+
/// Since both the key and value are encoded before saving to the map, there is no need to take them owned.
67+
pub fn put(&mut self, key: &K, value: &V) {
68+
let temp_key = temp_key_encode(key);
69+
let temp_value = temp_value_encode(value);
70+
self.raw_map.put(&temp_key, &temp_value);
71+
}
72+
73+
/// Clears value associated with key, and returns old value.
74+
pub fn remove(&mut self, key: &K) -> V {
75+
let temp_key = temp_key_encode(key);
76+
let value_raw = self.raw_map.remove(&temp_key);
77+
value_decode(value_raw)
78+
}
79+
80+
/// Returns true if there is a non-empty encoded value associated with the key.
81+
pub fn contains(&self, key: &K) -> bool {
82+
let temp_key = temp_key_encode(key);
83+
self.raw_map.contains(&temp_key)
84+
}
85+
}
86+
87+
fn temp_key_encode<M, K>(key: &K) -> ManagedRefMut<'static, M, ManagedBuffer<M>>
88+
where
89+
M: ManagedTypeApi + ErrorApi,
90+
K: TopEncode,
91+
{
92+
let mut key_ref = unsafe { ManagedBuffer::temp_const_ref_mut(const_handles::MBUF_TEMPORARY_1) };
93+
key_ref.overwrite(&[]);
94+
key.top_encode_or_handle_err(
95+
&mut *key_ref,
96+
ExitCodecErrorHandler::<M>::from(err_msg::SERIALIZER_ENCODE_ERROR),
97+
)
98+
.unwrap_infallible();
99+
key_ref
100+
}
101+
102+
fn temp_value_encode<M, V>(value: &V) -> ManagedRefMut<'static, M, ManagedBuffer<M>>
103+
where
104+
M: ManagedTypeApi + ErrorApi,
105+
V: TopEncode,
106+
{
107+
let mut value_ref =
108+
unsafe { ManagedBuffer::temp_const_ref_mut(const_handles::MBUF_TEMPORARY_2) };
109+
value_ref.overwrite(&[]);
110+
value
111+
.top_encode_or_handle_err(
112+
&mut *value_ref,
113+
ExitCodecErrorHandler::<M>::from(err_msg::SERIALIZER_ENCODE_ERROR),
114+
)
115+
.unwrap_infallible();
116+
value_ref
117+
}
118+
119+
fn value_decode<M, V>(value_raw: ManagedBuffer<M>) -> V
120+
where
121+
M: ManagedTypeApi + ErrorApi,
122+
V: TopDecode,
123+
{
124+
V::top_decode_or_handle_err(
125+
value_raw,
126+
ExitCodecErrorHandler::<M>::from(err_msg::SERIALIZER_ENCODE_ERROR),
127+
)
128+
.unwrap_infallible()
129+
}
Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
use multiversx_sc::api::ManagedTypeApi;
2+
use multiversx_sc::codec::derive::{NestedDecode, NestedEncode, TopDecode, TopEncode};
3+
use multiversx_sc::codec::{self, DecodeDefault, EncodeDefault};
4+
use multiversx_sc::proxy_imports::{TopDecodeOrDefault, TopEncodeOrDefault};
5+
use multiversx_sc::types::{BigUint, ManagedBuffer, ManagedMapEncoded};
6+
use multiversx_sc_scenario::api::StaticApi;
7+
8+
type ManagedMapEncodedBig =
9+
ManagedMapEncoded<StaticApi, BigUint<StaticApi>, ManagedBuffer<StaticApi>>;
10+
11+
fn assert_missing_key_int(mme: &ManagedMapEncoded<StaticApi, i32, i64>, key: i32) {
12+
assert!(!mme.contains(&key));
13+
assert_eq!(mme.get(&key), 0);
14+
}
15+
16+
#[test]
17+
fn managed_map_encoded_int_test() {
18+
let key = 1;
19+
let mut mme = ManagedMapEncoded::<StaticApi, i32, i64>::new();
20+
21+
assert_missing_key_int(&mme, key);
22+
23+
let value = 10;
24+
25+
mme.put(&key, &value);
26+
assert!(mme.contains(&key));
27+
assert_eq!(mme.get(&key), value);
28+
29+
assert_eq!(mme.remove(&key), value);
30+
assert_missing_key_int(&mme, key);
31+
32+
assert_eq!(mme.remove(&key), 0);
33+
assert_missing_key_int(&mme, key);
34+
35+
let value = 0;
36+
37+
mme.put(&key, &value);
38+
assert_missing_key_int(&mme, key);
39+
40+
assert_eq!(mme.remove(&key), 0);
41+
assert_missing_key_int(&mme, key);
42+
}
43+
44+
fn assert_missing_key_big(mme: &ManagedMapEncodedBig, key: &BigUint<StaticApi>) {
45+
assert!(!mme.contains(key));
46+
assert_eq!(mme.get(key), ManagedBuffer::new());
47+
}
48+
49+
#[test]
50+
fn managed_map_encoded_big_test() {
51+
let mut mme =
52+
ManagedMapEncoded::<StaticApi, BigUint<StaticApi>, ManagedBuffer<StaticApi>>::new();
53+
54+
let key = BigUint::from(1u32);
55+
assert_missing_key_big(&mme, &key);
56+
57+
let value = ManagedBuffer::from("abc");
58+
let empty = ManagedBuffer::new();
59+
60+
mme.put(&key, &value);
61+
assert!(mme.contains(&key));
62+
assert_eq!(&mme.get(&key), &value);
63+
64+
assert_eq!(&mme.remove(&key), &value);
65+
assert_missing_key_big(&mme, &key);
66+
67+
assert_eq!(&mme.remove(&key), &empty);
68+
assert_missing_key_big(&mme, &key);
69+
70+
mme.put(&key, &empty);
71+
assert_missing_key_big(&mme, &key);
72+
73+
assert_eq!(&mme.remove(&key), &empty);
74+
assert_missing_key_big(&mme, &key);
75+
}
76+
77+
#[derive(TopEncode, TopDecode)]
78+
pub struct StructKey {
79+
a: i32,
80+
b: i32,
81+
}
82+
83+
#[derive(NestedEncode, NestedDecode, PartialEq, Debug)]
84+
pub struct StructValue<M: ManagedTypeApi> {
85+
x: i32,
86+
y: ManagedBuffer<M>,
87+
}
88+
89+
fn assert_missing_opt_struct(
90+
mme: &ManagedMapEncoded<StaticApi, StructKey, Option<StructValue<StaticApi>>>,
91+
key: &StructKey,
92+
) {
93+
assert!(!mme.contains(key));
94+
assert_eq!(mme.get(key), None);
95+
}
96+
97+
#[test]
98+
fn managed_map_encoded_opt_struct_test() {
99+
let mut mme = ManagedMapEncoded::<StaticApi, StructKey, Option<StructValue<StaticApi>>>::new();
100+
101+
let key = StructKey { a: 1, b: 2 };
102+
assert_missing_opt_struct(&mme, &key);
103+
104+
let value = Some(StructValue {
105+
x: 3,
106+
y: ManagedBuffer::from("abc"),
107+
});
108+
109+
mme.put(&key, &value);
110+
assert!(mme.contains(&key));
111+
assert_eq!(&mme.get(&key), &value);
112+
113+
assert_eq!(&mme.remove(&key), &value);
114+
assert_missing_opt_struct(&mme, &key);
115+
116+
assert_eq!(&mme.remove(&key), &None);
117+
assert_missing_opt_struct(&mme, &key);
118+
119+
mme.put(&key, &None);
120+
assert_missing_opt_struct(&mme, &key);
121+
122+
assert_eq!(&mme.remove(&key), &None);
123+
assert_missing_opt_struct(&mme, &key);
124+
}
125+
126+
#[derive(TopEncode, TopDecode)]
127+
pub struct ManagedStructKey<M: ManagedTypeApi> {
128+
a: BigUint<M>,
129+
b: BigUint<M>,
130+
}
131+
132+
#[derive(TopEncodeOrDefault, TopDecodeOrDefault, PartialEq, Debug)]
133+
pub struct StructValueOrDefault<M: ManagedTypeApi> {
134+
x: i32,
135+
y: ManagedBuffer<M>,
136+
}
137+
138+
impl<M: ManagedTypeApi> EncodeDefault for StructValueOrDefault<M> {
139+
fn is_default(&self) -> bool {
140+
self.x == 0
141+
}
142+
}
143+
144+
impl<M: ManagedTypeApi> DecodeDefault for StructValueOrDefault<M> {
145+
fn default() -> Self {
146+
StructValueOrDefault {
147+
x: 0,
148+
y: ManagedBuffer::new(),
149+
}
150+
}
151+
}
152+
153+
fn assert_missing_struct(
154+
mme: &ManagedMapEncoded<
155+
StaticApi,
156+
ManagedStructKey<StaticApi>,
157+
StructValueOrDefault<StaticApi>,
158+
>,
159+
key: &ManagedStructKey<StaticApi>,
160+
) {
161+
assert!(!mme.contains(key));
162+
assert_eq!(mme.get(key), StructValueOrDefault::default());
163+
}
164+
165+
#[test]
166+
fn managed_map_encoded_struct_or_default_test() {
167+
let mut mme = ManagedMapEncoded::<
168+
StaticApi,
169+
ManagedStructKey<StaticApi>,
170+
StructValueOrDefault<StaticApi>,
171+
>::new();
172+
173+
let key = ManagedStructKey {
174+
a: 1u32.into(),
175+
b: 2u32.into(),
176+
};
177+
assert_missing_struct(&mme, &key);
178+
179+
let value = StructValueOrDefault {
180+
x: 3,
181+
y: ManagedBuffer::from("abc"),
182+
};
183+
let default = StructValueOrDefault::default();
184+
185+
mme.put(&key, &value);
186+
assert!(mme.contains(&key));
187+
assert_eq!(&mme.get(&key), &value);
188+
189+
assert_eq!(&mme.remove(&key), &value);
190+
assert_missing_struct(&mme, &key);
191+
192+
assert_eq!(&mme.remove(&key), &default);
193+
assert_missing_struct(&mme, &key);
194+
195+
mme.put(&key, &default);
196+
assert_missing_struct(&mme, &key);
197+
198+
assert_eq!(&mme.remove(&key), &default);
199+
assert_missing_struct(&mme, &key);
200+
}

0 commit comments

Comments
 (0)