diff --git a/contracts/feature-tests/basic-features/src/storage_mapper_get_at_address.rs b/contracts/feature-tests/basic-features/src/storage_mapper_get_at_address.rs index 35ef02b905..a3eff89cdb 100644 --- a/contracts/feature-tests/basic-features/src/storage_mapper_get_at_address.rs +++ b/contracts/feature-tests/basic-features/src/storage_mapper_get_at_address.rs @@ -1,5 +1,3 @@ -use multiversx_sc::storage::StorageKey; - multiversx_sc::imports!(); multiversx_sc::derive_imports!(); @@ -17,89 +15,71 @@ pub trait StorageMapperGetAtAddress { #[endpoint] fn is_empty_at_address(&self) -> bool { let address = self.contract_address().get(); - let mapper: SetMapper = - SetMapper::new_from_address(address, StorageKey::from("set_mapper")); - mapper.is_empty() + self.set_mapper_from_address(address).is_empty() } #[endpoint] fn contains_at_address(&self, item: u32) -> bool { let address = self.contract_address().get(); - let mapper: SetMapper = - SetMapper::new_from_address(address, StorageKey::from("set_mapper")); - mapper.contains(&item) + self.set_mapper_from_address(address).contains(&item) } #[endpoint] fn len_at_address(&self) -> usize { let address = self.contract_address().get(); - let mapper: SetMapper = - SetMapper::new_from_address(address, StorageKey::from("set_mapper")); - mapper.len() + self.set_mapper_from_address(address).len() } #[endpoint] fn next_at_address(&self, item: u32) -> u32 { let address = self.contract_address().get(); - let mapper: SetMapper = - SetMapper::new_from_address(address, StorageKey::from("set_mapper")); - mapper.next(&item).unwrap() + self.set_mapper_from_address(address).next(&item).unwrap() } #[endpoint] fn previous_at_address(&self, item: u32) -> u32 { let address = self.contract_address().get(); - let mapper: SetMapper = - SetMapper::new_from_address(address, StorageKey::from("set_mapper")); - mapper.previous(&item).unwrap() + self.set_mapper_from_address(address) + .previous(&item) + .unwrap() } #[endpoint] fn front_at_address(&self) -> u32 { let address = self.contract_address().get(); - let mapper: SetMapper = - SetMapper::new_from_address(address, StorageKey::from("set_mapper")); - mapper.front().unwrap() + self.set_mapper_from_address(address).front().unwrap() } #[endpoint] fn back_at_address(&self) -> u32 { let address = self.contract_address().get(); - let mapper: SetMapper = - SetMapper::new_from_address(address, StorageKey::from("set_mapper")); - mapper.back().unwrap() + self.set_mapper_from_address(address).back().unwrap() } #[endpoint] fn keys_at_address(&self) -> ManagedVec { let address = self.contract_address().get(); - let mapper: MapMapper = - MapMapper::new_from_address(address, StorageKey::from("map_mapper")); - mapper.keys().collect() + self.map_mapper_from_address(address).keys().collect() } #[endpoint] fn values_at_address(&self) -> ManagedVec { let address = self.contract_address().get(); - let mapper: MapMapper = - MapMapper::new_from_address(address, StorageKey::from("map_mapper")); - mapper.values().collect() + self.map_mapper_from_address(address).values().collect() } #[endpoint] fn contains_unordered_at_address(&self, item: u32) -> bool { let address = self.contract_address().get(); - let mapper: UnorderedSetMapper = - UnorderedSetMapper::new_from_address(address, StorageKey::from("unordered_set_mapper")); - mapper.contains(&item) + self.unordered_set_mapper_from_address(address) + .contains(&item) } #[endpoint] fn get_by_index(&self, index: usize) -> u32 { let address = self.contract_address().get(); - let mapper: UnorderedSetMapper = - UnorderedSetMapper::new_from_address(address, StorageKey::from("unordered_set_mapper")); - mapper.get_by_index(index) + self.unordered_set_mapper_from_address(address) + .get_by_index(index) } /// Storage to be called. For testing, this contract is deployed twice, @@ -107,12 +87,27 @@ pub trait StorageMapperGetAtAddress { #[storage_mapper("set_mapper")] fn set_mapper(&self) -> SetMapper; + #[storage_mapper_from_address("set_mapper")] + fn set_mapper_from_address(&self, address: ManagedAddress) -> SetMapper; + #[storage_mapper("map_mapper")] fn map_mapper(&self) -> MapMapper; + #[storage_mapper_from_address("map_mapper")] + fn map_mapper_from_address( + &self, + address: ManagedAddress, + ) -> MapMapper; + #[storage_mapper("unordered_set_mapper")] fn unordered_set_mapper(&self) -> UnorderedSetMapper; + #[storage_mapper_from_address("unordered_set_mapper")] + fn unordered_set_mapper_from_address( + &self, + address: ManagedAddress, + ) -> UnorderedSetMapper; + #[endpoint] fn fill_set_mapper(&self, value: u32) { for item in 1u32..=value { diff --git a/contracts/feature-tests/basic-features/src/storage_mapper_single.rs b/contracts/feature-tests/basic-features/src/storage_mapper_single.rs index f4604e3e73..69ea1280c5 100644 --- a/contracts/feature-tests/basic-features/src/storage_mapper_single.rs +++ b/contracts/feature-tests/basic-features/src/storage_mapper_single.rs @@ -1,5 +1,3 @@ -use multiversx_sc::storage::StorageKey; - multiversx_sc::imports!(); /// Storage mapper test. @@ -9,6 +7,12 @@ pub trait SingleValueMapperFeatures { #[storage_mapper("my_single_value_mapper")] fn map_my_single_value_mapper(&self) -> SingleValueMapper; + #[storage_mapper_from_address("my_single_value_mapper")] + fn map_my_single_value_mapper_from_address( + &self, + address: ManagedAddress, + ) -> SingleValueMapper; + #[endpoint] fn my_single_value_mapper_increment_1(&self, amount: BigInt) { let my_single_value_mapper = self.map_my_single_value_mapper(); @@ -55,12 +59,8 @@ pub trait SingleValueMapperFeatures { #[endpoint] fn is_empty_at_address_single_value_mapper(&self, address: ManagedAddress) -> bool { - let mapper: SingleValueMapper = SingleValueMapper::new_from_address( - address, - StorageKey::from("my_single_value_mapper"), - ); - - mapper.is_empty() + self.map_my_single_value_mapper_from_address(address) + .is_empty() } #[endpoint] diff --git a/contracts/feature-tests/basic-features/src/storage_mapper_vec.rs b/contracts/feature-tests/basic-features/src/storage_mapper_vec.rs index e8854806cb..b6205789f8 100644 --- a/contracts/feature-tests/basic-features/src/storage_mapper_vec.rs +++ b/contracts/feature-tests/basic-features/src/storage_mapper_vec.rs @@ -1,5 +1,3 @@ -use multiversx_sc::storage::StorageKey; - multiversx_sc::imports!(); /// Storage mapper test. @@ -9,6 +7,9 @@ pub trait VecMapperFeatures { #[storage_mapper("vec_mapper")] fn vec_mapper(&self) -> VecMapper; + #[storage_mapper_from_address("vec_mapper")] + fn vec_mapper_from_address(&self, address: ManagedAddress) -> VecMapper; + #[endpoint] fn vec_mapper_push(&self, item: u32) { let mut vec_mapper = self.vec_mapper(); @@ -22,8 +23,7 @@ pub trait VecMapperFeatures { #[view] fn vec_mapper_get_at_address(&self, address: ManagedAddress, index: usize) -> u32 { - let mapper = VecMapper::new_from_address(address, StorageKey::from("vec_mapper")); - mapper.get(index) + self.vec_mapper_from_address(address).get(index) } #[view] @@ -33,8 +33,6 @@ pub trait VecMapperFeatures { #[view] fn vec_mapper_len_at_address(&self, address: ManagedAddress) -> usize { - let mapper: VecMapper = - VecMapper::new_from_address(address, StorageKey::from("vec_mapper")); - mapper.len() + self.vec_mapper_from_address(address).len() } } diff --git a/contracts/feature-tests/basic-features/src/storage_mapper_whitelist.rs b/contracts/feature-tests/basic-features/src/storage_mapper_whitelist.rs index a02e706b91..ee9f255081 100644 --- a/contracts/feature-tests/basic-features/src/storage_mapper_whitelist.rs +++ b/contracts/feature-tests/basic-features/src/storage_mapper_whitelist.rs @@ -1,5 +1,3 @@ -use multiversx_sc::storage::StorageKey; - multiversx_sc::imports!(); #[multiversx_sc::module] @@ -21,9 +19,7 @@ pub trait StorageMapperWhitelistFeatures { #[endpoint] fn check_contains_at_address(&self, address: ManagedAddress, item: ManagedBuffer) -> bool { - let mapper = - WhitelistMapper::new_from_address(address, StorageKey::from("whitelistMapper")); - mapper.contains(&item) + self.whitelist_mapper_from_address(address).contains(&item) } #[endpoint] @@ -33,11 +29,16 @@ pub trait StorageMapperWhitelistFeatures { #[endpoint] fn require_contains_at_address(&self, address: ManagedAddress, item: ManagedBuffer) { - let mapper = - WhitelistMapper::new_from_address(address, StorageKey::from("whitelistMapper")); - mapper.require_whitelisted(&item) + self.whitelist_mapper_from_address(address) + .require_whitelisted(&item) } #[storage_mapper("whitelistMapper")] fn whitelist_mapper(&self) -> WhitelistMapper; + + #[storage_mapper_from_address("whitelistMapper")] + fn whitelist_mapper_from_address( + &self, + address: ManagedAddress, + ) -> WhitelistMapper; } diff --git a/framework/base/src/storage/mappers.rs b/framework/base/src/storage/mappers.rs index b6bac7f06b..d04b26e3e2 100644 --- a/framework/base/src/storage/mappers.rs +++ b/framework/base/src/storage/mappers.rs @@ -20,7 +20,7 @@ pub use bi_di_mapper::BiDiMapper; pub use linked_list_mapper::{LinkedListMapper, LinkedListNode}; pub use map_mapper::MapMapper; pub use map_storage_mapper::MapStorageMapper; -pub use mapper::{StorageClearable, StorageMapper}; +pub use mapper::{StorageClearable, StorageMapper, StorageMapperFromAddress}; pub use ordered_binary_tree_mapper::{ NodeId, OrderedBinaryTreeMapper, OrderedBinaryTreeNode, NULL_NODE_ID, }; diff --git a/framework/base/src/storage/mappers/address_to_id_mapper.rs b/framework/base/src/storage/mappers/address_to_id_mapper.rs index da487fa415..44c1237407 100644 --- a/framework/base/src/storage/mappers/address_to_id_mapper.rs +++ b/framework/base/src/storage/mappers/address_to_id_mapper.rs @@ -2,7 +2,7 @@ use core::marker::PhantomData; use super::{ set_mapper::{CurrentStorage, StorageAddress}, - StorageMapper, + StorageMapper, StorageMapperFromAddress, }; use crate::{ api::{ErrorApiImpl, StorageMapperApi}, @@ -42,11 +42,11 @@ where } } -impl AddressToIdMapper> +impl StorageMapperFromAddress for AddressToIdMapper> where SA: StorageMapperApi, { - pub fn new_from_address(address: ManagedAddress, base_key: StorageKey) -> Self { + fn new_from_address(address: ManagedAddress, base_key: StorageKey) -> Self { AddressToIdMapper { _phantom_api: PhantomData, address, diff --git a/framework/base/src/storage/mappers/bi_di_mapper.rs b/framework/base/src/storage/mappers/bi_di_mapper.rs index c47f38474c..ce0f24c159 100644 --- a/framework/base/src/storage/mappers/bi_di_mapper.rs +++ b/framework/base/src/storage/mappers/bi_di_mapper.rs @@ -11,7 +11,7 @@ use crate::{ use super::{ set_mapper::{CurrentStorage, StorageAddress}, - unordered_set_mapper, StorageMapper, UnorderedSetMapper, + unordered_set_mapper, StorageMapper, StorageMapperFromAddress, UnorderedSetMapper, }; use crate::{ abi::{TypeAbi, TypeDescriptionContainer, TypeName}, @@ -66,13 +66,13 @@ where } } -impl BiDiMapper> +impl StorageMapperFromAddress for BiDiMapper> where SA: StorageMapperApi, K: TopEncode + TopDecode + NestedEncode + NestedDecode + 'static + Default + PartialEq, V: TopEncode + TopDecode + NestedEncode + NestedDecode + 'static + Default + PartialEq, { - pub fn new_from_address(address: ManagedAddress, base_key: StorageKey) -> Self { + fn new_from_address(address: ManagedAddress, base_key: StorageKey) -> Self { let mut id_key = base_key.clone(); id_key.append_bytes(ID_SUFIX); diff --git a/framework/base/src/storage/mappers/linked_list_mapper.rs b/framework/base/src/storage/mappers/linked_list_mapper.rs index fd65fdec91..a259467c29 100644 --- a/framework/base/src/storage/mappers/linked_list_mapper.rs +++ b/framework/base/src/storage/mappers/linked_list_mapper.rs @@ -2,7 +2,7 @@ use core::marker::PhantomData; use super::{ set_mapper::{CurrentStorage, StorageAddress}, - StorageClearable, StorageMapper, + StorageClearable, StorageMapper, StorageMapperFromAddress, }; use crate::{ abi::{TypeAbi, TypeAbiFrom, TypeDescriptionContainer, TypeName}, @@ -118,12 +118,12 @@ where } } -impl LinkedListMapper> +impl StorageMapperFromAddress for LinkedListMapper> where SA: StorageMapperApi, T: TopEncode + TopDecode + NestedEncode + NestedDecode + Clone, { - pub fn new_from_address(address: ManagedAddress, base_key: StorageKey) -> Self { + fn new_from_address(address: ManagedAddress, base_key: StorageKey) -> Self { LinkedListMapper { _phantom_api: PhantomData, address, diff --git a/framework/base/src/storage/mappers/map_mapper.rs b/framework/base/src/storage/mappers/map_mapper.rs index aa5d105b9e..0da042334a 100644 --- a/framework/base/src/storage/mappers/map_mapper.rs +++ b/framework/base/src/storage/mappers/map_mapper.rs @@ -2,7 +2,7 @@ use core::marker::PhantomData; use super::{ set_mapper::{self, CurrentStorage, StorageAddress}, - SetMapper, StorageClearable, StorageMapper, + SetMapper, StorageClearable, StorageMapper, StorageMapperFromAddress, }; use crate::{ abi::{TypeAbi, TypeAbiFrom, TypeDescriptionContainer, TypeName}, @@ -99,13 +99,13 @@ where } } -impl MapMapper> +impl StorageMapperFromAddress for MapMapper> where SA: StorageMapperApi, K: TopEncode + TopDecode + NestedEncode + NestedDecode, V: TopEncode + TopDecode, { - pub fn new_from_address(address: ManagedAddress, base_key: StorageKey) -> Self { + fn new_from_address(address: ManagedAddress, base_key: StorageKey) -> Self { MapMapper { _phantom_api: PhantomData, address: address.clone(), diff --git a/framework/base/src/storage/mappers/map_storage_mapper.rs b/framework/base/src/storage/mappers/map_storage_mapper.rs index 5b101452b8..699a3bab36 100644 --- a/framework/base/src/storage/mappers/map_storage_mapper.rs +++ b/framework/base/src/storage/mappers/map_storage_mapper.rs @@ -2,7 +2,7 @@ use core::marker::PhantomData; use super::{ set_mapper::{self, CurrentStorage, StorageAddress}, - SetMapper, StorageClearable, StorageMapper, + SetMapper, StorageClearable, StorageMapper, StorageMapperFromAddress, }; use crate::{ api::StorageMapperApi, @@ -87,13 +87,13 @@ where } } -impl MapStorageMapper> +impl StorageMapperFromAddress for MapStorageMapper> where SA: StorageMapperApi, K: TopEncode + TopDecode + NestedEncode + NestedDecode, V: StorageMapper + StorageClearable, { - pub fn new_from_address(address: ManagedAddress, base_key: StorageKey) -> Self { + fn new_from_address(address: ManagedAddress, base_key: StorageKey) -> Self { MapStorageMapper { _phantom_api: PhantomData, base_key: base_key.clone(), diff --git a/framework/base/src/storage/mappers/mapper.rs b/framework/base/src/storage/mappers/mapper.rs index 3e21ad548e..89f9c80cd2 100644 --- a/framework/base/src/storage/mappers/mapper.rs +++ b/framework/base/src/storage/mappers/mapper.rs @@ -1,4 +1,4 @@ -use crate::{api::StorageMapperApi, storage::StorageKey}; +use crate::{api::StorageMapperApi, storage::StorageKey, types::ManagedAddress}; pub trait StorageMapper: 'static where @@ -8,6 +8,15 @@ where fn new(base_key: StorageKey) -> Self; } +pub trait StorageMapperFromAddress: 'static +where + SA: StorageMapperApi, +{ + /// Will be called automatically by the `#[storage_mapper_from_address]` + /// annotation generated code. + fn new_from_address(address: ManagedAddress, base_key: StorageKey) -> Self; +} + pub trait StorageClearable { /// Clears all the entries owned by the storage. fn clear(&mut self); diff --git a/framework/base/src/storage/mappers/queue_mapper.rs b/framework/base/src/storage/mappers/queue_mapper.rs index ac65764c36..9937736b01 100644 --- a/framework/base/src/storage/mappers/queue_mapper.rs +++ b/framework/base/src/storage/mappers/queue_mapper.rs @@ -2,7 +2,7 @@ use core::marker::PhantomData; use super::{ set_mapper::{CurrentStorage, StorageAddress}, - StorageClearable, StorageMapper, + StorageClearable, StorageMapper, StorageMapperFromAddress, }; use crate::{ abi::{TypeAbi, TypeAbiFrom, TypeDescriptionContainer, TypeName}, @@ -271,12 +271,12 @@ where } } -impl QueueMapper> +impl StorageMapperFromAddress for QueueMapper> where SA: StorageMapperApi, T: TopEncode + TopDecode, { - pub fn new_from_address(address: ManagedAddress, base_key: StorageKey) -> Self { + fn new_from_address(address: ManagedAddress, base_key: StorageKey) -> Self { QueueMapper { _phantom_api: PhantomData::, address, diff --git a/framework/base/src/storage/mappers/set_mapper.rs b/framework/base/src/storage/mappers/set_mapper.rs index 2ab1deb4f2..fbbb41ba3b 100644 --- a/framework/base/src/storage/mappers/set_mapper.rs +++ b/framework/base/src/storage/mappers/set_mapper.rs @@ -3,7 +3,7 @@ use core::marker::PhantomData; use storage_get_from_address::storage_get_len_from_address; pub use super::queue_mapper::Iter; -use super::{QueueMapper, StorageClearable, StorageMapper}; +use super::{QueueMapper, StorageClearable, StorageMapper, StorageMapperFromAddress}; use crate::{ abi::{TypeAbi, TypeAbiFrom, TypeDescriptionContainer, TypeName}, api::StorageMapperApi, @@ -95,12 +95,12 @@ where } } -impl SetMapper> +impl StorageMapperFromAddress for SetMapper> where SA: StorageMapperApi, T: TopEncode + TopDecode + NestedEncode + NestedDecode, { - pub fn new_from_address(address: ManagedAddress, base_key: StorageKey) -> Self { + fn new_from_address(address: ManagedAddress, base_key: StorageKey) -> Self { SetMapper { _phantom_api: PhantomData, address: address.clone(), diff --git a/framework/base/src/storage/mappers/single_value_mapper.rs b/framework/base/src/storage/mappers/single_value_mapper.rs index 1f121250ff..fa9448af69 100644 --- a/framework/base/src/storage/mappers/single_value_mapper.rs +++ b/framework/base/src/storage/mappers/single_value_mapper.rs @@ -2,7 +2,7 @@ use core::{borrow::Borrow, marker::PhantomData}; use super::{ set_mapper::{CurrentStorage, StorageAddress}, - StorageMapper, + StorageMapper, StorageMapperFromAddress, }; use crate::{ abi::{TypeAbi, TypeAbiFrom, TypeDescriptionContainer, TypeName}, @@ -44,13 +44,13 @@ where } } -impl SingleValueMapper> +impl StorageMapperFromAddress for SingleValueMapper> where SA: StorageMapperApi, T: TopEncode + TopDecode, { #[inline] - pub fn new_from_address(address: ManagedAddress, base_key: StorageKey) -> Self { + fn new_from_address(address: ManagedAddress, base_key: StorageKey) -> Self { SingleValueMapper { address, key: base_key, diff --git a/framework/base/src/storage/mappers/unique_id_mapper.rs b/framework/base/src/storage/mappers/unique_id_mapper.rs index 4ee1faa624..a1789d695a 100644 --- a/framework/base/src/storage/mappers/unique_id_mapper.rs +++ b/framework/base/src/storage/mappers/unique_id_mapper.rs @@ -8,7 +8,7 @@ use crate::{ use super::{ set_mapper::{CurrentStorage, StorageAddress}, - StorageMapper, VecMapper, + StorageMapper, StorageMapperFromAddress, VecMapper, }; use crate::{ abi::{TypeAbi, TypeDescriptionContainer, TypeName}, @@ -47,11 +47,11 @@ where } } -impl UniqueIdMapper> +impl StorageMapperFromAddress for UniqueIdMapper> where SA: StorageMapperApi, { - pub fn new_from_address(address: ManagedAddress, base_key: StorageKey) -> Self { + fn new_from_address(address: ManagedAddress, base_key: StorageKey) -> Self { Self { _address: address.clone(), base_key: base_key.clone(), diff --git a/framework/base/src/storage/mappers/unordered_set_mapper.rs b/framework/base/src/storage/mappers/unordered_set_mapper.rs index 254e56c6b5..7b59a31897 100644 --- a/framework/base/src/storage/mappers/unordered_set_mapper.rs +++ b/framework/base/src/storage/mappers/unordered_set_mapper.rs @@ -3,7 +3,7 @@ use core::marker::PhantomData; pub use super::vec_mapper::Iter; use super::{ set_mapper::{CurrentStorage, StorageAddress}, - StorageClearable, StorageMapper, VecMapper, + StorageClearable, StorageMapper, StorageMapperFromAddress, VecMapper, }; use crate::{ abi::{TypeAbi, TypeAbiFrom, TypeDescriptionContainer, TypeName}, @@ -47,12 +47,12 @@ where } } -impl UnorderedSetMapper> +impl StorageMapperFromAddress for UnorderedSetMapper> where SA: StorageMapperApi, T: TopEncode + TopDecode + NestedEncode + NestedDecode, { - pub fn new_from_address(address: ManagedAddress, base_key: StorageKey) -> Self { + fn new_from_address(address: ManagedAddress, base_key: StorageKey) -> Self { UnorderedSetMapper { _phantom_api: PhantomData, address: address.clone(), diff --git a/framework/base/src/storage/mappers/user_mapper.rs b/framework/base/src/storage/mappers/user_mapper.rs index 52039da9d5..8ed0db5fec 100644 --- a/framework/base/src/storage/mappers/user_mapper.rs +++ b/framework/base/src/storage/mappers/user_mapper.rs @@ -9,7 +9,7 @@ use crate::{ use super::{ set_mapper::{CurrentStorage, StorageAddress}, - StorageMapper, + StorageMapper, StorageMapperFromAddress, }; use crate::{ abi::{TypeAbi, TypeName}, @@ -54,11 +54,11 @@ where } } -impl UserMapper> +impl StorageMapperFromAddress for UserMapper> where SA: StorageMapperApi, { - pub fn new_from_address(address: ManagedAddress, base_key: StorageKey) -> Self { + fn new_from_address(address: ManagedAddress, base_key: StorageKey) -> Self { UserMapper { _phantom_api: PhantomData, address, diff --git a/framework/base/src/storage/mappers/vec_mapper.rs b/framework/base/src/storage/mappers/vec_mapper.rs index de2eb55d82..65b4818a98 100644 --- a/framework/base/src/storage/mappers/vec_mapper.rs +++ b/framework/base/src/storage/mappers/vec_mapper.rs @@ -1,6 +1,6 @@ use super::{ set_mapper::{CurrentStorage, StorageAddress}, - StorageClearable, StorageMapper, + StorageClearable, StorageMapper, StorageMapperFromAddress, }; use crate::{ abi::{TypeAbi, TypeAbiFrom, TypeDescriptionContainer, TypeName}, @@ -56,12 +56,12 @@ where } } -impl VecMapper> +impl StorageMapperFromAddress for VecMapper> where SA: StorageMapperApi, T: TopEncode + TopDecode, { - pub fn new_from_address(address: ManagedAddress, base_key: StorageKey) -> Self { + fn new_from_address(address: ManagedAddress, base_key: StorageKey) -> Self { let mut len_key = base_key.clone(); len_key.append_bytes(LEN_SUFFIX); diff --git a/framework/base/src/storage/mappers/whitelist_mapper.rs b/framework/base/src/storage/mappers/whitelist_mapper.rs index ac9ea7ea41..62111d2020 100644 --- a/framework/base/src/storage/mappers/whitelist_mapper.rs +++ b/framework/base/src/storage/mappers/whitelist_mapper.rs @@ -4,7 +4,7 @@ use multiversx_sc_codec::{TopDecode, TopEncode}; use super::{ set_mapper::{CurrentStorage, StorageAddress}, - SingleValueMapper, StorageMapper, + SingleValueMapper, StorageMapper, StorageMapperFromAddress, }; use crate::{ api::{ErrorApiImpl, StorageMapperApi}, @@ -45,12 +45,12 @@ where } } -impl WhitelistMapper> +impl StorageMapperFromAddress for WhitelistMapper> where SA: StorageMapperApi, T: NestedEncode + 'static, { - pub fn new_from_address(address: ManagedAddress, base_key: StorageKey) -> Self { + fn new_from_address(address: ManagedAddress, base_key: StorageKey) -> Self { Self { address, base_key, diff --git a/framework/derive/src/generate/auto_impl.rs b/framework/derive/src/generate/auto_impl.rs index 628a7af0e1..1d76e50e28 100644 --- a/framework/derive/src/generate/auto_impl.rs +++ b/framework/derive/src/generate/auto_impl.rs @@ -4,8 +4,8 @@ use super::{ auto_impl_event::generate_event_impl, auto_impl_proxy::generate_proxy_getter_impl, auto_impl_storage::{ - generate_clear_impl, generate_getter_impl, generate_is_empty_impl, generate_mapper_impl, - generate_setter_impl, + generate_clear_impl, generate_getter_impl, generate_is_empty_impl, + generate_mapper_from_address_impl, generate_mapper_impl, generate_setter_impl, }, }; @@ -33,6 +33,9 @@ fn generate_auto_impl(m: &Method, auto_impl: &AutoImpl) -> proc_macro2::TokenStr AutoImpl::StorageGetter { identifier } => generate_getter_impl(m, identifier), AutoImpl::StorageSetter { identifier } => generate_setter_impl(m, identifier), AutoImpl::StorageMapper { identifier } => generate_mapper_impl(m, identifier), + AutoImpl::StorageMapperFromAddress { identifier } => { + generate_mapper_from_address_impl(m, identifier) + }, AutoImpl::StorageIsEmpty { identifier } => generate_is_empty_impl(m, identifier), AutoImpl::StorageClear { identifier } => generate_clear_impl(m, identifier), AutoImpl::ProxyGetter => generate_proxy_getter_impl(m), diff --git a/framework/derive/src/generate/auto_impl_storage.rs b/framework/derive/src/generate/auto_impl_storage.rs index 94e7affa23..bb0c83d699 100644 --- a/framework/derive/src/generate/auto_impl_storage.rs +++ b/framework/derive/src/generate/auto_impl_storage.rs @@ -82,6 +82,31 @@ pub fn generate_mapper_impl(m: &Method, identifier: &str) -> proc_macro2::TokenS } } +pub fn generate_mapper_from_address_impl(m: &Method, identifier: &str) -> proc_macro2::TokenStream { + let msig = method_gen::generate_sig_with_attributes(m); + assert!( + !m.method_args.is_empty(), + "mapper from address must have at least one argument, for the value" + ); + let address_arg = &m.method_args[0]; + let address_pat = address_arg.pat.to_owned(); + let key_snippet = generate_key_snippet(&m.method_args[1..], identifier); + match m.return_type.clone() { + syn::ReturnType::Default => panic!("getter from address should return some value"), + syn::ReturnType::Type(_, ty) => { + quote! { + #msig { + #key_snippet + <#ty as multiversx_sc::storage::mappers::StorageMapperFromAddress>::new_from_address( + #address_pat, + ___key___ + ) + } + } + }, + } +} + pub fn generate_is_empty_impl(m: &Method, identifier: &str) -> proc_macro2::TokenStream { let msig = method_gen::generate_sig_with_attributes(m); let key_snippet = generate_key_snippet(m.method_args.as_slice(), identifier); diff --git a/framework/derive/src/model/method.rs b/framework/derive/src/model/method.rs index 776e39dfaa..22acf8eb78 100644 --- a/framework/derive/src/model/method.rs +++ b/framework/derive/src/model/method.rs @@ -7,6 +7,7 @@ pub enum AutoImpl { StorageGetter { identifier: String }, StorageSetter { identifier: String }, StorageMapper { identifier: String }, + StorageMapperFromAddress { identifier: String }, StorageIsEmpty { identifier: String }, StorageClear { identifier: String }, ProxyGetter, diff --git a/framework/derive/src/parse/attributes/attr_names.rs b/framework/derive/src/parse/attributes/attr_names.rs index 8df56f06f6..29784fc1c3 100644 --- a/framework/derive/src/parse/attributes/attr_names.rs +++ b/framework/derive/src/parse/attributes/attr_names.rs @@ -21,6 +21,7 @@ pub(super) static ATTR_CALLBACK_CALL_RESULT: &str = "call_result"; pub(super) static ATTR_STORAGE_GET: &str = "storage_get"; pub(super) static ATTR_STORAGE_SET: &str = "storage_set"; pub(super) static ATTR_STORAGE_MAPPER: &str = "storage_mapper"; +pub(super) static ATTR_STORAGE_MAPPER_FROM_ADDRESS: &str = "storage_mapper_from_address"; pub(super) static ATTR_STORAGE_IS_EMPTY: &str = "storage_is_empty"; pub(super) static ATTR_STORAGE_CLEAR: &str = "storage_clear"; pub(super) static ATTR_PROXY: &str = "proxy"; diff --git a/framework/derive/src/parse/attributes/storage_attr.rs b/framework/derive/src/parse/attributes/storage_attr.rs index 8a3e0d22c7..eebca83916 100644 --- a/framework/derive/src/parse/attributes/storage_attr.rs +++ b/framework/derive/src/parse/attributes/storage_attr.rs @@ -36,6 +36,20 @@ impl StorageMapperAttribute { } } +pub struct StorageMapperFromAddressAttribute { + pub identifier: String, +} + +impl StorageMapperFromAddressAttribute { + pub fn parse(attr: &syn::Attribute) -> Option { + is_attr_one_string_arg(attr, ATTR_STORAGE_MAPPER_FROM_ADDRESS).map(|arg_str| { + StorageMapperFromAddressAttribute { + identifier: arg_str, + } + }) + } +} + pub struct StorageIsEmptyAttribute { pub identifier: String, } diff --git a/framework/derive/src/parse/auto_impl_parse.rs b/framework/derive/src/parse/auto_impl_parse.rs index 24002e2139..eb19cc83a3 100644 --- a/framework/derive/src/parse/auto_impl_parse.rs +++ b/framework/derive/src/parse/auto_impl_parse.rs @@ -5,10 +5,11 @@ use super::attributes::*; fn assert_no_other_auto_impl(method: &Method) { assert!( method.implementation.is_no_implementation(), - "Only one auto-implementation can be specified at one time. Auto-implementations are: {}{}{}{}{}{}{}{}", + "Only one auto-implementation can be specified at one time. Auto-implementations are: {}{}{}{}{}{}{}{}{}", "`#[storage_get]`, ", "`#[storage_set]`, ", "`#[storage_mapper]`, ", + "`#[storage_mapper_from_address]`, ", "`#[storage_is_empty]`, ", "`#[storage_clear]`, ", "`#[proxy]`, ", @@ -72,6 +73,20 @@ pub fn process_storage_mapper_attribute(attr: &syn::Attribute, method: &mut Meth .is_some() } +pub fn process_storage_mapper_from_address_attribute( + attr: &syn::Attribute, + method: &mut Method, +) -> bool { + StorageMapperFromAddressAttribute::parse(attr) + .map(|storage_mapper_from_address| { + assert_no_other_auto_impl(&*method); + method.implementation = MethodImpl::Generated(AutoImpl::StorageMapperFromAddress { + identifier: storage_mapper_from_address.identifier, + }); + }) + .is_some() +} + pub fn process_storage_is_empty_attribute(attr: &syn::Attribute, method: &mut Method) -> bool { StorageIsEmptyAttribute::parse(attr) .map(|storage_is_empty| { diff --git a/framework/derive/src/parse/method_parse.rs b/framework/derive/src/parse/method_parse.rs index a8c8a111c7..481638068a 100644 --- a/framework/derive/src/parse/method_parse.rs +++ b/framework/derive/src/parse/method_parse.rs @@ -5,7 +5,8 @@ use super::{ auto_impl_parse::{ process_event_attribute, process_proxy_attribute, process_storage_clear_attribute, process_storage_get_attribute, process_storage_is_empty_attribute, - process_storage_mapper_attribute, process_storage_set_attribute, + process_storage_mapper_attribute, process_storage_mapper_from_address_attribute, + process_storage_set_attribute, }, extract_method_args, process_allow_multiple_var_args_attribute, process_callback_attribute, process_callback_raw_attribute, process_endpoint_attribute, process_external_view_attribute, @@ -127,6 +128,7 @@ fn process_attribute_second_pass( || process_storage_get_attribute(attr, method) || process_storage_set_attribute(attr, method) || process_storage_mapper_attribute(attr, method) + || process_storage_mapper_from_address_attribute(attr, method) || process_storage_is_empty_attribute(attr, method) || process_storage_clear_attribute(attr, method) || process_output_names_attribute(attr, method) diff --git a/framework/scenario/tests/test_hash_set_mapper.rs b/framework/scenario/tests/test_hash_set_mapper.rs index d52e50088a..44dcf395e2 100644 --- a/framework/scenario/tests/test_hash_set_mapper.rs +++ b/framework/scenario/tests/test_hash_set_mapper.rs @@ -1,6 +1,6 @@ use multiversx_sc::{ storage::{ - mappers::{SetMapper, StorageClearable, StorageMapper}, + mappers::{SetMapper, StorageClearable, StorageMapper, StorageMapperFromAddress}, StorageKey, }, types::ManagedAddress,