pub struct MapStorageMapper<SA, K, V, A = CurrentStorage>where
SA: StorageMapperApi,
K: TopEncode + TopDecode + NestedEncode + NestedDecode + 'static,
A: StorageAddress<SA>,
V: StorageMapper<SA> + StorageClearable,{ /* private fields */ }Expand description
A storage mapper implementing a map where values are themselves storage mappers (nested storage).
§Storage Layout
The MapStorageMapper uses a SetMapper to track keys and creates nested storage mappers for values:
-
Key tracking (via
SetMapper):base_key + ".info"→QueueMapperInfometadata for the key setbase_key + ".node_links" + node_id→ node structure (prev/next pointers)base_key + ".value" + node_id→ key valuebase_key + ".node_id" + encoded_key→ node ID lookup
-
Nested storage mappers:
base_key + ".storage" + encoded_key→ acts as base key for nested mapperV- Each nested mapper has its own sub-structure (e.g., if
VisVecMapper<SA, u32>, thenbase_key + ".storage" + key + ".len",base_key + ".storage" + key + ".item1", etc.)
§Main Operations
- Insert:
insert_default(key)- Adds a key with default-initialized nested mapper. O(1). - Remove:
remove(key)- Removes key and clears all nested storage. O(n) where n = nested mapper size. - Lookup:
get(key)- Returns the nested mapper for a key. O(1), lazy-creates mapper instance. - Contains:
contains_key(key)- Checks if key exists. O(1) with one storage read. - Entry API:
entry(key)- Provides entry-based manipulation for conditional initialization. - Iteration:
iter()- Iterates over (key, mapper) pairs;keys()- keys only;values()- mappers only.
§Key Characteristics
- Nested Storage: Values are not simple data but entire storage mappers (e.g.,
VecMapper,SetMapper) - Lazy Initialization: Nested mappers are created on-demand when accessed
- Composition: Enables complex hierarchical storage structures (e.g., map of lists, map of maps)
§Comparison with MapMapper
- MapMapper: Stores simple values directly (
MapMapper<SA, K, V>where V is a plain type) - MapStorageMapper: Stores nested mappers (
MapStorageMapper<SA, K, V>where V is a StorageMapper)
§Trade-offs
- Pros: Enables powerful nested data structures; each nested mapper is independent; type-safe composition.
- Cons: Higher storage overhead; removal is more expensive; complexity increases with nesting depth; each access creates mapper instance (lightweight but not zero-cost).
§Use Cases
- User-specific collections (e.g., map user address → their token balances as VecMapper)
- Category-based grouping (e.g., map category → items as SetMapper)
- Multi-level hierarchies (e.g., map project → map milestone → tasks as nested Mappers)
- Per-entity state machines (e.g., map entity_id → its own state storage)
§Example
// Create nested VecMapper for each user
mapper.insert_default(user1.clone());
mapper.insert_default(user2.clone());
// Get user's token list and add tokens
if let Some(mut user1_tokens) = mapper.get(&user1) {
user1_tokens.push(&100);
user1_tokens.push(&200);
}
if let Some(mut user2_tokens) = mapper.get(&user2) {
user2_tokens.push(&300);
}
// Check and access nested mapper
assert!(mapper.contains_key(&user1));
if let Some(user1_tokens) = mapper.get(&user1) {
assert_eq!(user1_tokens.len(), 2);
assert_eq!(user1_tokens.get(1), 100);
}
// Use entry API
mapper.entry(user1.clone())
.and_modify(|tokens| { tokens.push(&250); });
// Iterate over all users and their token lists
for (user, tokens) in mapper.iter() {
for token_id in tokens.iter() {
// Process each user's tokens
}
}
// Remove user and all their tokens
mapper.remove(&user2);
assert!(!mapper.contains_key(&user2));Implementations§
Source§impl<SA, K, V> MapStorageMapper<SA, K, V, CurrentStorage>where
SA: StorageMapperApi,
K: TopEncode + TopDecode + NestedEncode + NestedDecode,
V: StorageMapper<SA> + StorageClearable,
impl<SA, K, V> MapStorageMapper<SA, K, V, CurrentStorage>where
SA: StorageMapperApi,
K: TopEncode + TopDecode + NestedEncode + NestedDecode,
V: StorageMapper<SA> + StorageClearable,
Sourcepub fn insert_default(&mut self, k: K) -> bool
pub fn insert_default(&mut self, k: K) -> bool
Adds a default value for the key, if it is not already present.
If the map did not have this key present, true is returned.
If the map did have this value present, false is returned.
Source§impl<SA, A, K, V> MapStorageMapper<SA, K, V, A>where
SA: StorageMapperApi,
A: StorageAddress<SA>,
K: TopEncode + TopDecode + NestedEncode + NestedDecode,
V: StorageMapper<SA> + StorageClearable,
impl<SA, A, K, V> MapStorageMapper<SA, K, V, A>where
SA: StorageMapperApi,
A: StorageAddress<SA>,
K: TopEncode + TopDecode + NestedEncode + NestedDecode,
V: StorageMapper<SA> + StorageClearable,
pub fn keys(&self) -> Iter<'_, SA, A, K>
Sourcepub fn contains_key(&self, k: &K) -> bool
pub fn contains_key(&self, k: &K) -> bool
Returns true if the map contains a value for the specified key.
Sourcepub fn entry(&mut self, key: K) -> Entry<'_, SA, A, K, V>
pub fn entry(&mut self, key: K) -> Entry<'_, SA, A, K, V>
Gets the given key’s corresponding entry in the map for in-place manipulation.
Trait Implementations§
Source§impl<'a, SA, A, K, V> IntoIterator for &'a MapStorageMapper<SA, K, V, A>where
SA: StorageMapperApi,
A: StorageAddress<SA>,
K: TopEncode + TopDecode + NestedEncode + NestedDecode + 'static,
V: StorageMapper<SA> + StorageClearable,
impl<'a, SA, A, K, V> IntoIterator for &'a MapStorageMapper<SA, K, V, A>where
SA: StorageMapperApi,
A: StorageAddress<SA>,
K: TopEncode + TopDecode + NestedEncode + NestedDecode + 'static,
V: StorageMapper<SA> + StorageClearable,
Source§impl<SA, K, V> StorageClearable for MapStorageMapper<SA, K, V, CurrentStorage>where
SA: StorageMapperApi,
K: TopEncode + TopDecode + NestedEncode + NestedDecode,
V: StorageMapper<SA> + StorageClearable,
impl<SA, K, V> StorageClearable for MapStorageMapper<SA, K, V, CurrentStorage>where
SA: StorageMapperApi,
K: TopEncode + TopDecode + NestedEncode + NestedDecode,
V: StorageMapper<SA> + StorageClearable,
Source§impl<SA, K, V> StorageMapper<SA> for MapStorageMapper<SA, K, V, CurrentStorage>where
SA: StorageMapperApi,
K: TopEncode + TopDecode + NestedEncode + NestedDecode,
V: StorageMapper<SA> + StorageClearable,
impl<SA, K, V> StorageMapper<SA> for MapStorageMapper<SA, K, V, CurrentStorage>where
SA: StorageMapperApi,
K: TopEncode + TopDecode + NestedEncode + NestedDecode,
V: StorageMapper<SA> + StorageClearable,
Source§fn new(base_key: StorageKey<SA>) -> Self
fn new(base_key: StorageKey<SA>) -> Self
Will be called automatically by the
#[storage_mapper] annotation generated code.Source§impl<SA, K, V> StorageMapperFromAddress<SA> for MapStorageMapper<SA, K, V, ManagedAddress<SA>>where
SA: StorageMapperApi,
K: TopEncode + TopDecode + NestedEncode + NestedDecode,
V: StorageMapper<SA> + StorageClearable,
impl<SA, K, V> StorageMapperFromAddress<SA> for MapStorageMapper<SA, K, V, ManagedAddress<SA>>where
SA: StorageMapperApi,
K: TopEncode + TopDecode + NestedEncode + NestedDecode,
V: StorageMapper<SA> + StorageClearable,
Source§fn new_from_address(
address: ManagedAddress<SA>,
base_key: StorageKey<SA>,
) -> Self
fn new_from_address( address: ManagedAddress<SA>, base_key: StorageKey<SA>, ) -> Self
Will be called automatically by the
#[storage_mapper_from_address]
annotation generated code.Auto Trait Implementations§
impl<SA, K, V, A> Freeze for MapStorageMapper<SA, K, V, A>
impl<SA, K, V, A> RefUnwindSafe for MapStorageMapper<SA, K, V, A>where
SA: RefUnwindSafe,
A: RefUnwindSafe,
V: RefUnwindSafe,
<SA as HandleTypeInfo>::ManagedBufferHandle: RefUnwindSafe,
K: RefUnwindSafe,
impl<SA, K, V, A> Send for MapStorageMapper<SA, K, V, A>
impl<SA, K, V, A> Sync for MapStorageMapper<SA, K, V, A>
impl<SA, K, V, A> Unpin for MapStorageMapper<SA, K, V, A>
impl<SA, K, V, A> UnsafeUnpin for MapStorageMapper<SA, K, V, A>
impl<SA, K, V, A> UnwindSafe for MapStorageMapper<SA, K, V, A>where
SA: UnwindSafe,
A: UnwindSafe,
V: UnwindSafe,
<SA as HandleTypeInfo>::ManagedBufferHandle: UnwindSafe,
K: UnwindSafe,
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more