#[storage_item]
Expand description
Prepares the type to be fully compatible and usable with the storage.
It implements all necessary traits and calculates the storage key for types.
Packed
types don’t have a storage key, but non-packed types (like Mapping
, Lazy
etc.) require calculating the storage key during compilation.
Consider annotating structs and enums that are intended to be a part of the storage with this macro. If the type is packed then the usage of the macro is optional.
If the type is non-packed it is best to rely on automatic storage key
calculation via ink::storage_item
.
The usage of KEY: StorageKey
generic allows to propagate the parent’s storage key to
the type and offset the storage key of the type. It is helpful for non-packed types
that can be used several times in the contract. Each field should have a unique
storage key, so propagation of the parent’s storage key allows one to achieve it.
The macro should be called before derive
macros because it can change the type.
All required traits can be:
- Derived manually via
#[derive(...)]
. - Derived automatically via deriving of
scale::Decode
andscale::Encode
. - Derived via this macro.
§Example
§Trait implementation
use ink_prelude::vec::Vec;
use ink::storage::{
Lazy,
Mapping,
};
use ink::storage::traits::{
StorageKey,
StorableHint,
};
use ink::storage::traits::Storable;
// Deriving `scale::Decode` and `scale::Encode` also derives blanket implementation of all
// required traits to be storable.
#[derive(scale::Decode, scale::Encode)]
#[cfg_attr(
feature = "std",
derive(scale_info::TypeInfo, ink::storage::traits::StorageLayout)
)]
#[derive(Default, Debug)]
struct Packed {
s1: u128,
s2: Vec<u128>,
// Fails because `StorableHint` is only implemented for `Vec` where `T: Packed`.
// s3: Vec<NonPacked>,
}
// Example of how to define the packed type with generic.
#[derive(scale::Decode, scale::Encode)]
#[cfg_attr(
feature = "std",
derive(scale_info::TypeInfo, ink::storage::traits::StorageLayout)
)]
#[derive(Default, Debug)]
struct PackedGeneric<T: ink::storage::traits::Packed> {
s1: (u128, bool),
s2: Vec<T>,
s3: String,
}
// Example of how to define the non-packed type.
#[ink::storage_item]
#[derive(Default, Debug)]
struct NonPacked {
s1: Mapping<u32, u128>,
s2: Lazy<u128>,
}
// Example of how to define the non-packed generic type.
#[ink::storage_item(derive = false)]
#[derive(Storable, StorableHint, StorageKey)]
#[cfg_attr(
feature = "std",
derive(scale_info::TypeInfo, ink::storage::traits::StorageLayout)
)]
#[derive(Default, Debug)]
struct NonPackedGeneric<T>
where
T: Default + core::fmt::Debug,
T: ink::storage::traits::Packed,
{
s1: u32,
s2: T,
s3: Mapping<u128, T>,
}
// Example of how to define a complex packed type.
#[derive(scale::Decode, scale::Encode)]
#[cfg_attr(
feature = "std",
derive(scale_info::TypeInfo, ink::storage::traits::StorageLayout)
)]
#[derive(Default, Debug)]
struct PackedComplex {
s1: u128,
s2: Vec<u128>,
s3: Vec<Packed>,
}
// Example of how to define a complex non-packed type.
#[ink::storage_item]
#[derive(Default, Debug)]
struct NonPackedComplex<KEY: StorageKey> {
s1: (String, u128, Packed),
s2: Mapping<u128, u128>,
s3: Lazy<u128>,
s4: Mapping<u128, Packed>,
s5: Lazy<NonPacked>,
s6: PackedGeneric<Packed>,
s7: NonPackedGeneric<Packed>,
// Fails because: the trait `ink::storage::traits::Packed` is not implemented for `NonPacked`
// s8: Mapping<u128, NonPacked>,
}
§Header Arguments
The #[ink::storage_item]
macro can be provided with an additional comma-separated
header argument:
-
derive: bool
The
derive
configuration parameter is used to enable/disable auto deriving of all required storage traits.Usage Example:
use ink::storage::Mapping; use ink::storage::traits::{ StorableHint, StorageKey, Storable, }; #[ink::storage_item(derive = false)] #[derive(StorableHint, Storable, StorageKey)] struct NonPackedGeneric<T: ink::storage::traits::Packed> { s1: u32, s2: Mapping<u128, T>, }
Default value: true.