Skip to content

Commit

Permalink
chore: update docs for Vector and store collections (#896)
Browse files Browse the repository at this point in the history
Co-authored-by: Phuong Nguyen <[email protected]>
  • Loading branch information
austinabell and ChaoticTempest authored Aug 25, 2022
1 parent 13fbfc9 commit cfd6dce
Show file tree
Hide file tree
Showing 12 changed files with 78 additions and 19 deletions.
3 changes: 3 additions & 0 deletions near-sdk/src/collections/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
//! Collections that offer an alternative to standard containers from `std::collections::*` by
//! utilizing the underlying blockchain trie storage more efficiently.
//!
//! The updated version of this module lives in [`near_sdk::store`](crate::store),
//! where the data structures are more optimized and have a closer API to [`std::collections`].
//!
//! For example, the following smart contract does not work with state efficiently, because it will
//! load the entire `HashMap` at the beginning of the contract call, and will save it entirely at
//! the end, in cases when there is state modification. This is fine for small number of elements,
Expand Down
5 changes: 4 additions & 1 deletion near-sdk/src/store/index_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@ impl<T> IndexMap<T>
where
T: BorshSerialize,
{
/// Create new index map. Prefixes storage accesss with the prefix provided.
/// Create new index map. This creates a mapping of `u32` -> `T` in storage.
///
/// This prefix can be anything that implements [`IntoStorageKey`]. The prefix is used when
/// storing and looking up values in storage to ensure no collisions with other collections.
pub fn new<S>(prefix: S) -> Self
where
S: IntoStorageKey,
Expand Down
5 changes: 5 additions & 0 deletions near-sdk/src/store/lazy/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,11 @@ impl<T> Lazy<T>
where
T: BorshSerialize,
{
/// Initializes new lazily loaded value with a given storage prefix and the value to initialize
/// it with.
///
/// This prefix can be anything that implements [`IntoStorageKey`]. The prefix is used when
/// storing and looking up values in storage to ensure no collisions with other collections.
pub fn new<S>(key: S, value: T) -> Self
where
S: IntoStorageKey,
Expand Down
2 changes: 1 addition & 1 deletion near-sdk/src/store/lazy_option/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ where
if cfg!(feature = "expensive-debug") {
self.get().fmt(f)
} else {
f.debug_struct("LazyOption").field("storage_key", &self.storage_key).finish()
f.debug_struct("LazyOption").field("storage_key", &self.prefix).finish()
}
}
}
22 changes: 11 additions & 11 deletions near-sdk/src/store/lazy_option/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ where
T: BorshSerialize,
{
/// Key bytes to index the contract's storage.
storage_key: Box<[u8]>,
prefix: Box<[u8]>,

/// Cached value which is lazily loaded and deserialized from storage.
#[borsh_skip]
Expand All @@ -48,8 +48,11 @@ impl<T> LazyOption<T>
where
T: BorshSerialize,
{
/// Create a new lazy option with the given `storage_key` and the initial value.
pub fn new<S>(storage_key: S, value: Option<T>) -> Self
/// Create a new lazy option with the given `prefix` and the initial value.
///
/// This prefix can be anything that implements [`IntoStorageKey`]. The prefix is used when
/// storing and looking up values in storage to ensure no collisions with other collections.
pub fn new<S>(prefix: S, value: Option<T>) -> Self
where
S: IntoStorageKey,
{
Expand All @@ -58,10 +61,7 @@ where
None => CacheEntry::new_cached(None),
};

Self {
storage_key: storage_key.into_storage_key().into_boxed_slice(),
cache: OnceCell::from(cache),
}
Self { prefix: prefix.into_storage_key().into_boxed_slice(), cache: OnceCell::from(cache) }
}

/// Updates the value with a new value. This does not load the current value from storage.
Expand All @@ -85,9 +85,9 @@ where
}

match v.value().as_ref() {
Some(value) => serialize_and_store(&self.storage_key, value),
Some(value) => serialize_and_store(&self.prefix, value),
None => {
env::storage_remove(&self.storage_key);
env::storage_remove(&self.prefix);
}
}

Expand All @@ -106,15 +106,15 @@ where
/// The load from storage only happens once, and if the value is already cached, it will not
/// be reloaded.
pub fn get(&self) -> &Option<T> {
let entry = self.cache.get_or_init(|| load_and_deserialize(&self.storage_key));
let entry = self.cache.get_or_init(|| load_and_deserialize(&self.prefix));
entry.value()
}

/// Returns a reference to the lazily loaded optional.
/// The load from storage only happens once, and if the value is already cached, it will not
/// be reloaded.
pub fn get_mut(&mut self) -> &mut Option<T> {
self.cache.get_or_init(|| load_and_deserialize(&self.storage_key));
self.cache.get_or_init(|| load_and_deserialize(&self.prefix));
let entry = self.cache.get_mut().unwrap_or_else(|| env::abort());
entry.value_mut()
}
Expand Down
5 changes: 4 additions & 1 deletion near-sdk/src/store/lookup_map/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,10 @@ where
K: BorshSerialize + Ord,
V: BorshSerialize,
{
/// Create a new map. Use `key_prefix` as a unique prefix for keys.
/// Create a new [`LookupMap`] with the prefix provided.
///
/// This prefix can be anything that implements [`IntoStorageKey`]. The prefix is used when
/// storing and looking up values in storage to ensure no collisions with other collections.
///
/// # Examples
///
Expand Down
4 changes: 4 additions & 0 deletions near-sdk/src/store/lookup_set/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ impl<T> LookupSet<T, Identity>
where
T: BorshSerialize + Ord,
{
/// Initialize new [`LookupSet`] with the prefix provided.
///
/// This prefix can be anything that implements [`IntoStorageKey`]. The prefix is used when
/// storing and looking up values in storage to ensure no collisions with other collections.
#[inline]
pub fn new<S>(prefix: S) -> Self
where
Expand Down
23 changes: 20 additions & 3 deletions near-sdk/src/store/mod.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,29 @@
//! Collections and types used when interacting with storage.
//!
//! This module is the updated version of [`near_sdk::collections`](crate::collections) where the
//! data structures are more optimized and have a closer API to [`std::collections`].
//!
//! These collections are more scalable versions of [`std::collections`] when used as contract
//! state because it allows values to be lazily loaded and stored based on what is actually
//! interacted with.
//!
//! Fundamentally, a contract's storage is a key/value store where both keys and values are just
//! [`Vec<u8>`]. If you want to store some structured data, for example, [`Vec<Account>`], one way
//! to achieve that would be to serialize the Vec to bytes and store that. This has a drawback in
//! that accessing or modifying a single element would require reading the whole `Vec` from the
//! storage.
//!
//! That's where `store` module helps. Its collections are backed by a key value store.
//! For example, a store::Vector is stored as several key-value pairs, where indices are the keys.
//! So, accessing a single element would only load this specific element.
//!
//! It can be expensive to load all values into memory, and because of this, `serde`
//! [`Serialize`](serde::Serialize) and [`Deserialize`](serde::Deserialize) traits are
//! intentionally not implemented. If you want to return all values from a storage collection from
//! a function, consider using pagination with the collection iterators.
//!
//! All of the collections implement [`BorshSerialize`](borsh::BorshSerialize) and
//! [`BorshDeserialize`](borsh::BorshDeserialize) to be able to store the metadata of the
//! collections to be able to access all values. Because only metadata is serialized, these
//! structures should not be used as a borsh return value from a function.
//!
//! The collections are as follows:
//!
//! Sequences:
Expand Down
4 changes: 4 additions & 0 deletions near-sdk/src/store/tree_map/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,10 @@ where
K: BorshSerialize + Ord,
V: BorshSerialize,
{
/// Initialize new [`TreeMap`] with the prefix provided.
///
/// This prefix can be anything that implements [`IntoStorageKey`]. The prefix is used when
/// storing and looking up values in storage to ensure no collisions with other collections.
pub fn new<S>(prefix: S) -> Self
where
S: IntoStorageKey,
Expand Down
5 changes: 4 additions & 1 deletion near-sdk/src/store/unordered_map/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,10 @@ where
K: BorshSerialize + Ord,
V: BorshSerialize,
{
/// Create a new map. Use `key_prefix` as a unique prefix for keys.
/// Create a new iterable map. Use `prefix` as a unique prefix for keys.
///
/// This prefix can be anything that implements [`IntoStorageKey`]. The prefix is used when
/// storing and looking up values in storage to ensure no collisions with other collections.
///
/// # Examples
///
Expand Down
12 changes: 12 additions & 0 deletions near-sdk/src/store/unordered_set/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,18 @@ impl<T> UnorderedSet<T, Sha256>
where
T: BorshSerialize + Ord,
{
/// Create a new iterable set. Use `prefix` as a unique prefix for keys.
///
/// This prefix can be anything that implements [`IntoStorageKey`]. The prefix is used when
/// storing and looking up values in storage to ensure no collisions with other collections.
///
/// # Examples
///
/// ```
/// use near_sdk::store::UnorderedSet;
///
/// let mut map: UnorderedSet<String> = UnorderedSet::new(b"b");
/// ```
#[inline]
pub fn new<S>(prefix: S) -> Self
where
Expand Down
7 changes: 6 additions & 1 deletion near-sdk/src/store/vec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,8 @@ where

/// Create new vector with zero elements. Prefixes storage accesss with the prefix provided.
///
/// This prefix can be anything that implements [`IntoStorageKey`].
/// This prefix can be anything that implements [`IntoStorageKey`]. The prefix is used when
/// storing and looking up values in storage to ensure no collisions with other collections.
///
/// # Examples
///
Expand Down Expand Up @@ -247,6 +248,10 @@ where
/// Sets a value at a given index to the value provided. This does not shift values after the
/// index to the right.
///
/// The reason to use this over modifying with [`Vector::get_mut`] or
/// [`IndexMut::index_mut`](core::ops::IndexMut::index_mut) is to avoid loading the existing
/// value from storage. This method will just write the new value.
///
/// # Panics
///
/// Panics if `index` is out of bounds.
Expand Down

0 comments on commit cfd6dce

Please sign in to comment.