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, which is the implementation supported
by external host functions provided by the chain, and a
test one. The latter one is
useful for testing since it provides an implementation that is easier to
construct, execute, and inspect during unit testing.
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
Example
#[derive(Serial, DeserialWithState)]
#[concordium(state_parameter = "S")]
struct MyState<S: HasStateApi> {
inner: StateMap<u64, u64, S>,
}
#[init(contract = "mycontract")]
fn contract_init<S: HasStateApi>(
_ctx: &impl HasInitContext,
state_builder: &mut StateBuilder<S>,
) -> InitResult<MyState<S>> {
Ok(MyState {
inner: state_builder.new_map(),
})
}
#[receive(contract = "mycontract", name = "receive", return_value = "Option<u64>")]
fn contract_receive<S: HasStateApi>(
_ctx: &impl HasReceiveContext,
host: &impl HasHost<MyState<S>, StateApiType = S>, // 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> {
inner: StateMap<u64, u64, S>,
}
fn incorrect_replace<S: HasStateApi>(
state_builder: &mut StateBuilder<S>,
state: &mut MyState<S>,
) {
// 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<S: HasStateApi>(
state_builder: &mut StateBuilder<S>,
state: &mut MyState<S>,
) {
state.inner.clear_flat();
}
Or alternatively
fn correct_replace<S: HasStateApi>(
state_builder: &mut StateBuilder<S>,
state: &mut MyState<S>,
) {
let old_map = mem::replace(&mut state.inner, state_builder.new_map());
old_map.delete()
}
Implementations
sourceimpl<K, V, S> StateMap<K, V, S> where
S: HasStateApi,
K: Serialize,
V: Serial + DeserialWithState<S>,
impl<K, V, S> StateMap<K, V, S> where
S: HasStateApi,
K: Serialize,
V: Serial + DeserialWithState<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(&self, key: &K) -> Option<StateRefMut<'_, V, S>>
pub fn get_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.
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.
sourceimpl<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>ⓘNotable traits for StateMapIter<'a, K, V, S>impl<'a, K, V, S: HasStateApi> Iterator for StateMapIter<'a, K, V, S> where
K: Deserial + 'a,
V: DeserialWithState<S> + 'a, type Item = (StateRef<'a, K>, StateRef<'a, V>);
pub fn iter(&self) -> StateMapIter<'_, K, V, S>ⓘNotable traits for StateMapIter<'a, K, V, S>impl<'a, K, V, S: HasStateApi> Iterator for StateMapIter<'a, K, V, S> where
K: Deserial + 'a,
V: DeserialWithState<S> + 'a, type Item = (StateRef<'a, K>, StateRef<'a, V>);
K: Deserial + 'a,
V: DeserialWithState<S> + 'a, type Item = (StateRef<'a, K>, StateRef<'a, V>);
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>ⓘNotable traits for StateMapIterMut<'a, K, V, S>impl<'a, K, V: Serial, S: HasStateApi> Iterator for StateMapIterMut<'a, K, V, S> where
K: Deserial + 'a,
V: DeserialWithState<S> + 'a,
S::EntryType: 'a, type Item = (StateRef<'a, K>, StateRefMut<'a, V, S>);
pub fn iter_mut(&mut self) -> StateMapIterMut<'_, K, V, S>ⓘNotable traits for StateMapIterMut<'a, K, V, S>impl<'a, K, V: Serial, S: HasStateApi> Iterator for StateMapIterMut<'a, K, V, S> where
K: Deserial + 'a,
V: DeserialWithState<S> + 'a,
S::EntryType: 'a, type Item = (StateRef<'a, K>, StateRefMut<'a, V, S>);
K: Deserial + 'a,
V: DeserialWithState<S> + 'a,
S::EntryType: 'a, type Item = (StateRef<'a, K>, StateRefMut<'a, V, S>);
Like iter, but allows modifying the values during iteration.
Trait Implementations
sourceimpl<K, V, S> Deletable for StateMap<K, V, S> where
S: HasStateApi,
K: Serialize,
V: Serial + DeserialWithState<S> + Deletable,
impl<K, V, S> Deletable for StateMap<K, V, S> where
S: HasStateApi,
K: Serialize,
V: Serial + DeserialWithState<S> + Deletable,
sourceimpl<K, V, S> DeserialWithState<S> for StateMap<K, V, S> where
S: HasStateApi,
impl<K, V, S> DeserialWithState<S> for StateMap<K, V, S> where
S: HasStateApi,
sourcefn deserial_with_state<R: Read>(state: &S, source: &mut R) -> ParseResult<Self>
fn deserial_with_state<R: Read>(state: &S, source: &mut R) -> ParseResult<Self>
Attempt to read a structure from a given source and state, failing if an error occurs during deserialization or reading. Read more
sourceimpl<T, V, S: HasStateApi> StateClone<S> for StateMap<T, V, S>
impl<T, V, S: HasStateApi> StateClone<S> for StateMap<T, V, S>
sourceunsafe fn clone_state(&self, cloned_state_api: &S) -> Self
unsafe fn clone_state(&self, cloned_state_api: &S) -> Self
Make a clone of the type while using the cloned_state_api
. Read more
Auto Trait Implementations
impl<K, V, S> RefUnwindSafe for StateMap<K, V, S> where
K: RefUnwindSafe,
S: RefUnwindSafe,
V: RefUnwindSafe,
impl<K, V, S> Send for StateMap<K, V, S> where
K: Send,
S: Send,
V: Send,
impl<K, V, S> Sync for StateMap<K, V, S> where
K: Sync,
S: Sync,
V: Sync,
impl<K, V, S> Unpin for StateMap<K, V, S> where
K: Unpin,
S: Unpin,
V: Unpin,
impl<K, V, S> UnwindSafe for StateMap<K, V, S> where
K: UnwindSafe,
S: UnwindSafe,
V: UnwindSafe,
Blanket Implementations
sourceimpl<T> BorrowMut<T> for T where
T: ?Sized,
impl<T> BorrowMut<T> for T where
T: ?Sized,
const: unstable · sourcefn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more