Struct concordium_std::StateMap
source · pub struct StateMap<K, V, S> { /* private fields */ }
Expand description
A high-level map based on the low-level key-value store, which is the interface provided by the chain.
In most situations, this collection should be preferred over
BTreeMap
and HashMap
since it will be more efficient to
lookup and update since costs to lookup and update will grow very slowly
with the size of the collection. In contrast, using BTreeMap
and
HashMap
almost always entails their serialization, which is linear
in the size of the collection.
The cost of updates to the map are dependent on the length of K
(in bytes)
and the size of the data stored (V
). Short keys are therefore ideal.
New maps can be constructed using the
new_map
method on the StateBuilder
.
/// In an init method:
let mut map1 = state_builder.new_map();
/// In a receive method:
let mut map2 = host.state_builder().new_map();
§Type parameters
The map StateMap<K, V, S>
is parametrized by the type of keys K
, the
type of values V
and the type of the low-level state S
. In line with
other Rust collections, e.g., BTreeMap
and HashMap
constructing the statemap via new_map
does not
require anything specific from K
and V
. However most operations do
require that K
is serializable and V
can be stored and loaded in the
context of the low-level state S
.
This concretely means that K
must implement
Serialize
and V
has to implement
Serial
and
DeserialWithState<S>
. In practice, this means
that keys must be flat, meaning that it cannot have any references to the
low-level state. This is almost all types, except StateBox
, StateMap
and StateSet
and types containing these.
However values may contain references to the low-level state, in particular maps may be nested.
§Low-level state S
The type parameter S
is extra compared to usual Rust collections. As
mentioned above it specifies the low-level state
implementation. This library provides two such
implementations. The “external” one (StateApi
), which is the
implementation supported by external host functions provided by the chain,
and a test one. The latter one
is only useful for testing with the deprecated
test_infrastructure
module.
In user code this type parameter should generally be treated as boilerplate,
and contract entrypoints should always be stated in terms of a generic type
S
that implements HasStateApi and defaults to
StateApi
, unless you intend to use the deprecated testing library.
§Example
#[derive(Serial, DeserialWithState)]
#[concordium(state_parameter = "S")]
struct MyState<S: HasStateApi = StateApi> {
inner: StateMap<u64, u64, S>,
}
#[init(contract = "mycontract")]
fn contract_init(_ctx: &InitContext, state_builder: &mut StateBuilder) -> InitResult<MyState> {
Ok(MyState {
inner: state_builder.new_map(),
})
}
#[receive(contract = "mycontract", name = "receive", return_value = "Option<u64>")]
fn contract_receive(
_ctx: &ReceiveContext,
host: &Host<MyState>, // the same low-level state must be propagated throughout
) -> ReceiveResult<Option<u64>> {
let state = host.state();
Ok(state.inner.get(&0).map(|v| *v))
}
§Caution
StateMap
s must be explicitly deleted when they are no longer needed,
otherwise they will remain in the contract’s state, albeit unreachable.
struct MyState<S: HasStateApi = StateApi> {
inner: StateMap<u64, u64, S>,
}
fn incorrect_replace(state_builder: &mut StateBuilder, state: &mut MyState) {
// The following is incorrect. The old value of `inner` is not properly deleted.
// from the state.
state.inner = state_builder.new_map(); // ⚠️
}
Instead, either the map should be cleared or explicitly deleted.
fn correct_replace(state_builder: &mut StateBuilder, state: &mut MyState) {
state.inner.clear_flat();
}
Or alternatively
fn correct_replace(state_builder: &mut StateBuilder, state: &mut MyState) {
let old_map = mem::replace(&mut state.inner, state_builder.new_map());
old_map.delete()
}
Implementations§
source§impl<K, V, S> StateMap<K, V, S>
impl<K, V, S> StateMap<K, V, S>
sourcepub fn get(&self, key: &K) -> Option<StateRef<'_, V>>
pub fn get(&self, key: &K) -> Option<StateRef<'_, V>>
Lookup the value with the given key. Return None if there is no value with the given key.
sourcepub fn get_mut(&mut self, key: &K) -> Option<StateRefMut<'_, V, S>>
pub fn get_mut(&mut self, key: &K) -> Option<StateRefMut<'_, V, S>>
Lookup a mutable reference to the value with the given key. Return None if there is no value with the given key.
sourcepub fn insert(&mut self, key: K, value: V) -> Option<V>
pub fn insert(&mut self, key: K, value: V) -> Option<V>
Inserts the value with the given key. If a value already exists at the given key it is replaced and the old value is returned.
Caution: If Option<V>
is to be deleted and contains a data structure
prefixed with State
(such as StateBox or
StateMap), then it is important to call
Deletable::delete
on the value returned
when you’re finished with it. Otherwise, it will remain in the
contract state.
sourcepub fn clear(&mut self)where
V: Deletable,
pub fn clear(&mut self)where
V: Deletable,
Clears the map, removing all key-value pairs.
This also includes values pointed at, if V
, for example, is a
StateBox. If applicable use clear_flat
instead.
sourcepub fn clear_flat(&mut self)where
V: Deserial,
pub fn clear_flat(&mut self)where
V: Deserial,
Clears the map, removing all key-value pairs.
This should be used over clear
if it is
applicable. It avoids recursive deletion of values since the
values are required to be flat.
Unfortunately it is not possible to automatically choose between these implementations. Once Rust gets trait specialization then this might be possible.
sourcepub fn remove_and_get(&mut self, key: &K) -> Option<V>
pub fn remove_and_get(&mut self, key: &K) -> Option<V>
Remove a key from the map, returning the value at the key if the key was previously in the map.
Caution: If V
is a StateBox, StateMap, then it is
important to call Deletable::delete
on the value returned when
you’re finished with it. Otherwise, it will remain in the contract
state.
source§impl<K, V, S> StateMap<K, V, S>where
S: HasStateApi,
impl<K, V, S> StateMap<K, V, S>where
S: HasStateApi,
sourcepub fn iter(&self) -> StateMapIter<'_, K, V, S> ⓘ
pub fn iter(&self) -> StateMapIter<'_, K, V, S> ⓘ
Get an iterator over the key-value pairs of the map. The iterator returns values in increasing order of keys, where keys are ordered lexicographically via their serializations.
sourcepub fn iter_mut(&mut self) -> StateMapIterMut<'_, K, V, S> ⓘ
pub fn iter_mut(&mut self) -> StateMapIterMut<'_, K, V, S> ⓘ
Like iter, but allows modifying the values during iteration.