StorageMap
A StorageMap
, a.k.a. a hash table, is a structure which associates a value v
with a key k
. The key is used to find the position in the table (memory) where the value is stored.
The benefit of a hash table is that no matter where the value is in the table the computation required to find the location of that value is constant i.e. it has an order of 1 O(1)
.
Sway provides a flexible StorageMap
because it uses generics for both k
& v
with the caveat that k
and v
have to be a single value. The value can be a struct, tuple, array etc. therefore if you'd like to have a complex k
or v
then the data needs to be wrapped into a single type.
Declaration
The StorageMap
type is included in the prelude therefore we do not need to import it. We'll be using msg_sender()
in the subsequent section so we'll import that here.
After the import we initialize our StorageMap
as described in the initialization section.
storage {
// k = Identity, v = u64
balance: StorageMap<Identity, u64> = StorageMap::<Identity, u64> {},
// k = (Identity, u64), v = bool
user: StorageMap<(Identity, u64), bool> = StorageMap::<(Identity, u64), bool> {},
}
There are two storage
variables: balance
& user
. balance
takes a single value as the key while user
wraps two values into a tuple and uses that as a key.
Reading from Storage
Retrieving data from a storage variable is done through the .get(key)
method. That is to say that we state which storage variable we would like to read from and append .get()
to the end while providing the key for the data that we want to retrieve. The method get
returns an Option
; if there is no value for key
in the map, get
will return None
.
In this example we wrap the Identity
of the caller with their provided id
into a tuple and use that as the key.
#[storage(read)]
fn reading_from_storage(id: u64) {
let user = storage.user.get((msg_sender().unwrap(), id)).read();
}
This contract method handles the returned Option
by calling unwrap_or
to set user
to zero if the map user
doesn't have an entry for the key.
Writing to Storage
Writing to storage is similar to reading. The difference is that we use a different method .insert(key, value)
.
In this example we retrieve the balance of the caller and then increment their balance by 1.
#[storage(read, write)]
fn writing_to_storage() {
let balance = storage.balance.get(msg_sender().unwrap()).read();
storage.balance.insert(msg_sender().unwrap(), balance + 1);
}