Skip to main content

MapStorageMapper

Struct MapStorageMapper 

Source
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:

  1. Key tracking (via SetMapper):

    • base_key + ".info"QueueMapperInfo metadata for the key set
    • base_key + ".node_links" + node_id → node structure (prev/next pointers)
    • base_key + ".value" + node_id → key value
    • base_key + ".node_id" + encoded_key → node ID lookup
  2. Nested storage mappers:

    • base_key + ".storage" + encoded_key → acts as base key for nested mapper V
    • Each nested mapper has its own sub-structure (e.g., if V is VecMapper<SA, u32>, then base_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>

Source

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

pub fn remove(&mut self, k: &K) -> bool

Removes the entry from the map.

If the entry was removed, true is returned.

If the map didn’t contain an entry with this key, 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,

Source

pub fn get(&self, k: &K) -> Option<V>

Gets a reference to the value in the entry.

Source

pub fn keys(&self) -> Iter<'_, SA, A, K>

Source

pub fn is_empty(&self) -> bool

Returns true if the map contains no elements.

Source

pub fn len(&self) -> usize

Returns the number of elements in the map.

Source

pub fn contains_key(&self, k: &K) -> bool

Returns true if the map contains a value for the specified key.

Source

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.

Source

pub fn values(&self) -> Values<'_, SA, A, K, V>

An iterator visiting all values in arbitrary order. The iterator element type is &'a V.

Source

pub fn iter(&self) -> Iter<'_, SA, A, K, V>

An iterator visiting all key-value pairs in arbitrary order. The iterator element type is (&'a K, &'a V).

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,

Source§

type Item = (K, V)

The type of the elements being iterated over.
Source§

type IntoIter = Iter<'a, SA, A, K, V>

Which kind of iterator are we turning this into?
Source§

fn into_iter(self) -> Self::IntoIter

Creates an iterator from a value. Read more
Source§

impl<SA, K, V> StorageClearable for MapStorageMapper<SA, K, V, CurrentStorage>

Source§

fn clear(&mut self)

Clears all the entries owned by the storage.
Source§

impl<SA, K, V> StorageMapper<SA> for MapStorageMapper<SA, K, V, CurrentStorage>

Source§

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>>

Source§

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>

§

impl<SA, K, V, A> Send for MapStorageMapper<SA, K, V, A>
where SA: Send, A: Send, V: Send, <SA as HandleTypeInfo>::ManagedBufferHandle: Send, K: Send,

§

impl<SA, K, V, A> Sync for MapStorageMapper<SA, K, V, A>
where SA: Sync, A: Sync, V: Sync, <SA as HandleTypeInfo>::ManagedBufferHandle: Sync, K: Sync,

§

impl<SA, K, V, A> Unpin for MapStorageMapper<SA, K, V, A>
where SA: Unpin, A: Unpin, V: Unpin, <SA as HandleTypeInfo>::ManagedBufferHandle: Unpin, K: Unpin,

§

impl<SA, K, V, A> UnsafeUnpin for MapStorageMapper<SA, K, V, A>

§

impl<SA, K, V, A> UnwindSafe for MapStorageMapper<SA, K, V, A>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T, U> TypeAbiFrom<TypeAbiUniversalInput<T>> for U