Struct ink_storage::StorageVec

source ·
pub struct StorageVec<V: Packed, KeyType: StorageKey = AutoKey> { /* private fields */ }
Expand description

A vector of values (elements) directly on contract storage.

§Important

StorageVec requires its own pre-defined storage key where to store values. By default, the is automatically calculated using AutoKey during compilation. However, anyone can specify a storage key using ManualKey. Specifying the storage key can be helpful for upgradeable contracts or you want to be resistant to future changes of storage key calculation strategy.

§Differences between ink::prelude::vec::Vec and StorageVec

Any Vec<T> will exhibit Packed storage layout; where StorageVec stores each value under it’s own storage key.

Hence, any read or write from or to a Vec on storage will load or store all of its elements.

This can be undesirable: The cost of reading or writing a single element grows linearly corresponding to the number of elements in the vector (its length). Additionally, the maximum capacity of the whole vector is limited by the size of the static buffer used during ABI encoding and decoding (default 16 KiB).

StorageVec on the other hand allows to access each element individually. Thus, it can theoretically grow to infinite size. However, we currently limit the length at 2 ^ 32 elements. In practice, even if the vector elements are single bytes, it’ll allow to store more than 4 GB data in blockchain storage.

§Caveats

Iterators are not provided. StorageVec is expected to be used to store a lot elements, where iterating through the elements would be rather inefficient (naturally, it is still possible to manually iterate over the elements using a loop).

For the same reason, operations which would require re-ordering stored elements are not supported. Examples include inserting and deleting elements at arbitrary positions or sorting elements.

The decision whether to use Vec<T> or StorageVec can be seen as an optimization problem with several factors:

  • How large you expect the vector to grow
  • The size of individual elements being stored
  • How frequently reads, writes and iterations happen

For example, if a vector is expected to stay small but is frequently iterated over. Choosing a Vec<T> instead of StorageVec will be preferred as individual storage reads are much more expensive as opposed to retrieving and decoding the whole collection with a single storage read.

§Storage Layout

At given StorageKey K, the length of the StorageVec is hold. Each element E is then stored under a combination of the StorageVec key K and the elements index.

Given StorageVec under key K, the storage key E of the Nth element is calculated as follows:

E = scale::Encode((K, N))

Implementations§

source§

impl<V, KeyType> StorageVec<V, KeyType>
where V: Packed, KeyType: StorageKey,

source

pub const fn new() -> Self

Creates a new empty StorageVec.

source

pub fn len(&self) -> u32

Returns the number of elements in the vector, also referred to as its length.

The length is cached; subsequent calls (without writing to the vector) won’t trigger additional storage reads.

source

pub fn is_empty(&self) -> bool

Returns true if the vector contains no elements.

source

pub fn push<T>(&mut self, value: &T)
where T: Storable + EncodeLike<V>,

Appends an element to the back of the vector.

§Panics
  • If the vector is at capacity (max. of 2 ^ 32 elements).
  • If the value overgrows the static buffer size.
  • If there was already a value at the current index.
source

pub fn try_push<T>(&mut self, value: &T) -> Result<(), Error>
where T: Storable + EncodeLike<V>,

Try to append an element to the back of the vector.

Returns:

  • Ok(()) if the value was inserted successfully
  • Err(_) if the encoded value exceeds the static buffer size.
source

pub fn pop(&mut self) -> Option<V>

Clears the last element from the storage and returns it. Shrinks the length of the vector by one. Returns None if the vector is empty or if the last element was already cleared from storage.

§Panics
  • If the value overgrows the static buffer size.
source

pub fn try_pop(&mut self) -> Option<Result<V, Error>>

Try to clear and return the last element from storage. Shrinks the length of the vector by one. Returns None if the vector is empty.

Returns

Some(Ok(_)) containing the value if it existed and was decoded successfully. Some(Err(_)) if the value existed but its length exceeds the static buffer size. None if the vector is empty.

source

pub fn peek(&self) -> Option<V>

Get a copy of the last element without removing it from storage.

§Panics
  • If the value overgrows the static buffer size.
source

pub fn try_peek(&self) -> Option<Result<V, Error>>

Try to get a copy of the last element without removing it from storage.

Returns:

Some(Ok(_)) containing the value if it existed and was decoded successfully. Some(Err(_)) if the value existed but its length exceeds the static buffer size. None if the vector is empty.

source

pub fn get(&self, index: u32) -> Option<V>

Access an element at given index.

Returns None if there was no value at the index.

§Panics
  • If encoding the element exceeds the static buffer size.
source

pub fn try_get(&self, index: u32) -> Option<Result<V>>

Try to access an element at given index.

Returns:

  • Some(Ok(_)) containing the value if it existed and was decoded successfully.
  • Some(Err(_)) if the value existed but its length exceeds the static buffer size.
  • None if there was no value at index.
source

pub fn set<T>(&mut self, index: u32, value: &T) -> Option<u32>
where T: Storable + EncodeLike<V>,

Set the value at given index.

§Panics
  • If the index is out of bounds.
  • If decoding the element exceeds the static buffer size.
source

pub fn try_set<T>( &mut self, index: u32, value: &T, ) -> Result<Option<u32>, Error>
where T: Storable + EncodeLike<V>,

Try to set the value at given index.

Returns:

  • Ok(Some(_)) if the value was inserted successfully, containing the size in bytes of the pre-existing value at the specified key if any.
  • Ok(None) if the insert was successful but there was no pre-existing value.
  • Err(ink_env::Error::BufferTooSmall) if the encoded value exceeds the static buffer size
  • Err(ink_env::Error::ReturnError([ink_env::ReturnErrorCode::KeyNotFound])) if the index is out of bounds.
§Panics

Panics if index exceeds the length of the vector.

source

pub fn clear(&mut self)

Delete all elements from storage.

§Warning

This iterates through all elements in the vector; complexity is O(n). It might not be possible to clear large vectors within a single block!

source

pub fn clear_at(&mut self, index: u32)

Clears the value of the element at index. It doesn’t change the length of the vector.

§Panics

Panics if index exceeds the length of the vector.

Trait Implementations§

source§

impl<V, KeyType> Debug for StorageVec<V, KeyType>
where V: Packed, KeyType: StorageKey,

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl<V, KeyType> Default for StorageVec<V, KeyType>
where V: Packed, KeyType: StorageKey,

source§

fn default() -> Self

Returns the “default value” for a type. Read more
source§

impl<V, KeyType> FromIterator<V> for StorageVec<V, KeyType>
where V: Packed + EncodeLike<V>, KeyType: StorageKey,

source§

fn from_iter<T: IntoIterator<Item = V>>(iter: T) -> Self

Creates a value from an iterator. Read more
source§

impl<V, KeyType> Storable for StorageVec<V, KeyType>
where V: Packed, KeyType: StorageKey,

source§

fn encode<T: Output + ?Sized>(&self, _dest: &mut T)

Convert self to a slice and append it to the destination.
source§

fn decode<I: Input>(_input: &mut I) -> Result<Self, Error>

Attempt to deserialize the value from input.
source§

fn encoded_size(&self) -> usize

The exact number of bytes this type consumes in the encoded form.
source§

impl<V, Key, InnerKey> StorableHint<Key> for StorageVec<V, InnerKey>
where V: Packed, Key: StorageKey, InnerKey: StorageKey,

§

type Type = StorageVec<V, Key>

Storable type with storage key inside.
§

type PreferredKey = InnerKey

The storage key that the type prefers. It can be overwritten by an auto-generated storage key.
source§

impl<V, KeyType> StorageKey for StorageVec<V, KeyType>
where V: Packed, KeyType: StorageKey,

source§

const KEY: Key = KeyType::KEY

Storage key of the type.
source§

fn key(&self) -> u32

Returns the storage key.
source§

impl<V, KeyType> StorageLayout for StorageVec<V, KeyType>
where V: Packed + StorageLayout + TypeInfo + 'static, KeyType: StorageKey + TypeInfo + 'static,

source§

fn layout(_: &Key) -> Layout

Returns the static storage layout of Self. Read more
source§

impl<V, KeyType> TypeInfo for StorageVec<V, KeyType>
where Lazy<u32, KeyType>: TypeInfo + 'static, Mapping<u32, V, KeyType>: TypeInfo + 'static, V: Packed + TypeInfo + 'static, KeyType: StorageKey + TypeInfo + 'static,

§

type Identity = StorageVec<V, KeyType>

The type identifying for which type info is provided. Read more
source§

fn type_info() -> Type

Returns the static type identifier for Self.

Auto Trait Implementations§

§

impl<V, KeyType = AutoKey> !Freeze for StorageVec<V, KeyType>

§

impl<V, KeyType = AutoKey> !RefUnwindSafe for StorageVec<V, KeyType>

§

impl<V, KeyType> Send for StorageVec<V, KeyType>

§

impl<V, KeyType = AutoKey> !Sync for StorageVec<V, KeyType>

§

impl<V, KeyType> Unpin for StorageVec<V, KeyType>

§

impl<V, KeyType> UnwindSafe for StorageVec<V, KeyType>

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

§

type Output = T

Should always be Self
§

impl<T> SaturatedConversion for T

§

fn saturated_from<T>(t: T) -> Self
where Self: UniqueSaturatedFrom<T>,

Convert from a value of T into an equivalent instance of Self. Read more
§

fn saturated_into<T>(self) -> T
where Self: UniqueSaturatedInto<T>,

Consume self to return an equivalent value of T. Read more
source§

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

§

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

§

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

impl<T, S> UniqueSaturatedInto<T> for S
where T: Bounded, S: TryInto<T>,

§

fn unique_saturated_into(self) -> T

Consume self to return an equivalent value of T.
§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

§

fn vzip(self) -> V

§

impl<T> StaticTypeInfo for T
where T: TypeInfo + 'static,

§

impl<T> TypeId for T
where T: Debug + Default,