1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
//! Collections and types used when interacting with storage.
//!
//! ## Benchmarks of comparison with [`std::collections`]:
//!
//! To help you understand how cost-effective near collections are in terms of gas usage compared to native ones,
//! take a look at this investigation: [Near benchmarking github](https://github.com/volodymyr-matselyukh/near-benchmarking).
//!
//! The results of the investigation can be found here: [Results](https://docs.google.com/spreadsheets/d/1ThsBlNR6_Ol9K8cU7BRXNN73PblkTbx0VW_njrF633g/edit?gid=0#gid=0).
//!
//! If your collection has up to 100 entries, it's acceptable to use the native collection, as it might be simpler
//! since you don't have to manage prefixes as we do with near collections.
//! However, if your collection has 1,000 or more entries, it's better to use a near collection. The investigation
//! mentioned above shows that running the contains method on a native [`std::collections::HashSet<i32>`] **consumes 41% more gas**
//! compared to a near [`crate::store::IterableSet<i32>`].
//!
//! ## FAQ: most collections of this [`module`](self) persist on `Drop` and `flush`
//! Unlike containers in [`near_sdk::collections`](crate::collections) module, most containers in current [`module`](self) cache all changes
//! and loads and only update values that are changed in storage after it’s dropped through it’s [`Drop`] implementation.
//! Note that [`LookupSet`] is an exception and writes directly to storage on each operation
//! without using an in-memory cache or a `flush`-based persistence mechanism.
//!
//! These changes can be updated in storage before the container variable is dropped by using
//! the container's `flush` method, e.g. [`IterableMap::flush`](crate::store::IterableMap::flush) ([`IterableMap::drop`](crate::store::IterableMap::drop) uses it in implementation too).
//!
//! ```rust,no_run
//! # use near_sdk::{log, near};
//! use near_sdk::store::IterableMap;
//!
//! #[near(contract_state)]
//! #[derive(Debug)]
//! pub struct Contract {
//! greeting_map: IterableMap<String, String>,
//! }
//!
//! # impl Default for Contract {
//! # fn default() -> Self {
//! # let prefix = b"gr_pr";
//! # Self {
//! # greeting_map: IterableMap::new(prefix.as_slice()),
//! # }
//! # }
//! # }
//!
//! #[near]
//! impl Contract {
//! pub fn mutating_method(&mut self, argument: String) {
//! self.greeting_map.insert("greeting".into(), argument);
//! near_sdk::env::log_str(&format!("State of contract mutated: {:#?}", self));
//! }
//! }
//! // expanded #[near] macro call on a contract method definition:
//! // ...
//! # let argument = "hello world".to_string();
//! let mut contract: Contract = ::near_sdk::env::state_read().unwrap_or_default();
//! // call of the original `mutating_method` as defined in source code prior to expansion
//! Contract::mutating_method(&mut contract, argument);
//! ::near_sdk::env::state_write(&contract);
//! // Drop on `contract` is called! `IterableMap` is only `flush`-ed here <====
//! // ...
//! ```
//!
//! ## General description
//!
//! 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's also a bad practice to have a native collection properties as a top level properties of your contract.
//! The contract will load all the properties before the contract method invocation. That means that all your native
//! collections will be fully loaded into memory even if they are not used in the method you invoke.
//!
//! 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.
//!
//! ## Calls to **host functions**, used in implementation:
//!
//! * [`near_sdk::env::storage_write`](crate::env::storage_write)
//! * [`near_sdk::env::storage_read`](crate::env::storage_read)
//! * [`near_sdk::env::storage_remove`](crate::env::storage_remove)
//! * [`near_sdk::env::storage_has_key`](crate::env::storage_has_key)
//!
//! ## Module's glossary:
//!
//! The collections are as follows:
//!
//! Sequences:
//!
//! - [`Vector`]: Analogous to [`Vec`] but not contiguous and persisted to storage.
//!
//! Maps:
//!
//! - [`LookupMap`]: Wrapper around key-value storage interactions, similar to
//! [`UnorderedMap`]/[`std::collections::HashMap`] except that keys are not persisted and cannot be
//! iterated over.
//!
//! - [`UnorderedMap`]: __DEPRECATED__ storage version of [`std::collections::HashMap`]. No ordering
//! guarantees.
//! - [`IterableMap`]: a replacement with better iteration performance for [`UnorderedMap`], which is being deprecated.
//!
//! - [`TreeMap`] (`unstable`): Storage version of [`std::collections::BTreeMap`]. Ordered by key,
//! which comes at the cost of more expensive lookups and iteration.
//!
//! Sets:
//!
//! - [`LookupSet`]: Non-iterable storage version of [`std::collections::HashSet`].
//!
//! - [`UnorderedSet`]: __DEPRECATED__ analogous to [`std::collections::HashSet`], and is an iterable
//! version of [`LookupSet`] and persisted to storage.
//! - [`IterableSet`]: a replacement with better iteration performance for [`UnorderedSet`], which is being deprecated.
//!
//! Basic Types:
//!
//! - [`Lazy<T>`](Lazy): Lazily loaded type that can be used in place of a type `T`.
//! Will only be loaded when interacted with and will persist on [`Drop`].
//!
//! - [`LazyOption<T>`](LazyOption): Lazily loaded, optional type that can be used in
//! place of a type [`Option<T>`](Option). Will only be loaded when interacted with and will
//! persist on [`Drop`].
//!
//! * More information about collections can be found in [NEAR documentation](https://docs.near.org/build/smart-contracts/anatomy/collections)
//! * Benchmarking results of the NEAR-SDK store collections vs native collections can be found in [github](https://github.com/volodymyr-matselyukh/near-benchmarking)
pub use Lazy;
pub use LazyOption;
pub use Vector;
pub use LookupMap;
pub use LookupSet;
pub use IterableMap;
pub use IterableSet;
pub use UnorderedMap;
pub use UnorderedSet;
pub use TreeMap;
pub use IndexMap;
pub
pub use FreeList;
/// Storage key hash function types and trait to override map hash functions.
pub const ERR_INCONSISTENT_STATE: &str = "The collection is in an inconsistent state. Did previous smart \
contract execution terminate unexpectedly?";
pub const ERR_NOT_EXIST: &str = "Key does not exist in map";