ic_storage/adapter/map.rs
1//! Governed map collection implementation.
2use super::error::{CollectionError as Error, Result, ensure};
3use super::tree::Tree;
4use super::{MapIter, Memory, Storable};
5use crate::DefaultMemoryImpl;
6use crate::RuntimeMemory;
7use std::ops::RangeBounds;
8
9/// Governed ordered map backed by Storage’s owned B-tree and reusable blocks.
10pub struct StableBTreeMap<K: Storable + Ord + Clone, V: Storable, M: Memory = DefaultMemoryImpl> {
11 inner: Tree<K, V, RuntimeMemory<M>>,
12}
13impl<K: Storable + Ord + Clone, V: Storable, M: Memory> StableBTreeMap<K, V, M> {
14 /// Create a collection only in zero-page memory.
15 ///
16 /// # Errors
17 /// Refuses nonempty memory, invalid encoding or capacity exhaustion before writes.
18 pub fn create(memory: RuntimeMemory<M>) -> Result<Self> {
19 ensure(memory.size() == 0, Error::NotEmpty)?;
20 Self::reset(memory)
21 }
22
23 /// Deliberately replace any contents in this admitted allocation.
24 ///
25 /// # Errors
26 /// Returns encoding, capacity or structural admission errors.
27 pub fn reset(memory: RuntimeMemory<M>) -> Result<Self> {
28 Ok(Self {
29 inner: Tree::reset(memory)?,
30 })
31 }
32
33 /// Load retained collection state without initializing a replacement.
34 ///
35 /// # Errors
36 /// Refuses empty, foreign or corrupt memory and incompatible bounds without writing.
37 pub fn load(memory: RuntimeMemory<M>) -> Result<Self> {
38 Ok(Self {
39 inner: Tree::load(memory)?,
40 })
41 }
42 /// Clear entries while retaining this allocation's exclusive lease.
43 ///
44 /// # Errors
45 /// Reports a poisoned owner or metadata encoding/capacity refusal.
46 pub fn clear(&mut self) -> Result<()> {
47 self.inner.clear()
48 }
49 /// Set the heap budget for cached, validated routing nodes; zero disables it.
50 ///
51 /// Caching is disabled initially. Changing the budget discards cached nodes.
52 /// The budget accounts for buffer capacities and cache bookkeeping, excluding
53 /// allocator overhead and nodes retained by an active iterator. External
54 /// values are never cached. Writes invalidate affected nodes; reloads start
55 /// cold. The exclusive backing-custody contract applies while caching.
56 /// Slot capacity scales with the budget; upper routing nodes take priority
57 /// over deeper colliding nodes. Very small budgets may retain no nodes.
58 pub fn set_node_cache_budget(&mut self, bytes: usize) {
59 self.inner.set_cache_budget(bytes);
60 }
61 /// Reserve a minimum virtual extent without exposing or duplicating the lease.
62 ///
63 /// Returns the map on both success and ordinary growth refusal. Entries are
64 /// preserved; the cached tree remains unchanged.
65 /// Backing traps follow the host transaction contract.
66 ///
67 /// `minimum` is an absolute virtual extent in 65,536-byte Wasm pages, not an
68 /// entry count or additional pages. Existing extents never shrink. A request
69 /// already covered performs no growth or writes. This reserves backing only:
70 /// it does not promise that any particular number or encoding of entries fits.
71 /// Callers own their byte/page budget and must qualify it for their codecs;
72 /// internal node-layout constants are not a supported capacity contract.
73 pub fn reserve_pages(
74 self,
75 minimum: u64,
76 ) -> (Self, std::result::Result<(), crate::RuntimeGrowError>) {
77 let additional = minimum.saturating_sub(self.inner.memory.size());
78 let result = self.inner.memory.grow(additional).map(|_| ());
79 (self, result)
80 }
81 /// Observe the virtual extent in 65,536-byte pages while retaining the lease.
82 ///
83 /// Consumes and returns the map while retaining the exclusive lease.
84 /// Observing the allocation performs no writes or growth.
85 /// This is allocated extent, not free space or guaranteed entry capacity.
86 #[must_use]
87 pub fn allocated_pages(self) -> (Self, u64) {
88 let pages = self.inner.memory.size();
89 (self, pages)
90 }
91 /// Perform `insert` on the governed ordered map.
92 ///
93 /// # Errors
94 /// Rejects encoding, decoding, structural or capacity errors before committing writes.
95 pub fn insert(&mut self, key: K, value: V) -> Result<Option<V>> {
96 self.inner.insert(key, value)
97 }
98 /// Perform `get` on the governed ordered map.
99 ///
100 /// # Errors
101 /// Reports structural, integrity or application decoding failures without writing.
102 pub fn get(&self, key: &K) -> Result<Option<V>> {
103 self.inner.get(key)
104 }
105 /// Perform `contains_key` on the governed ordered map.
106 ///
107 /// # Errors
108 /// Reports structural, integrity or application decoding failures without writing.
109 pub fn contains_key(&self, key: &K) -> Result<bool> {
110 self.inner.contains_key(key)
111 }
112 /// Perform `is_empty` on the governed ordered map.
113 ///
114 /// # Errors
115 /// Reports invalid region metadata or incompatible codec bounds.
116 pub fn is_empty(&self) -> bool {
117 self.inner.len() == 0
118 }
119 /// Perform `len` on the governed ordered map.
120 pub fn len(&self) -> u64 {
121 self.inner.len()
122 }
123 /// Perform `remove` on the governed ordered map.
124 ///
125 /// # Errors
126 /// Rejects decoding or structural errors before committing removal.
127 pub fn remove(&mut self, key: &K) -> Result<Option<V>> {
128 self.inner.remove(key)
129 }
130 /// Perform `first_key_value` on the governed ordered map.
131 ///
132 /// # Errors
133 /// Reports invalid structure, integrity failures or application codec errors.
134 pub fn first_key_value(&self) -> Result<Option<(K, V)>> {
135 self.iter()
136 .next()
137 .map(|entry| entry?.into_pair())
138 .transpose()
139 }
140 /// Perform `last_key_value` on the governed ordered map.
141 ///
142 /// # Errors
143 /// Reports invalid structure, integrity failures or application codec errors.
144 pub fn last_key_value(&self) -> Result<Option<(K, V)>> {
145 self.iter()
146 .next_back()
147 .map(|entry| entry?.into_pair())
148 .transpose()
149 }
150 /// Perform `iter` on the governed ordered map.
151 pub fn iter(&self) -> MapIter<'_, K, V, M> {
152 self.inner.range(..)
153 }
154 /// Perform `range` on the governed ordered map.
155 pub fn range(&self, key_range: impl RangeBounds<K>) -> MapIter<'_, K, V, M> {
156 self.inner.range(key_range)
157 }
158 /// Perform `keys` on the governed ordered map.
159 pub fn keys(&self) -> impl DoubleEndedIterator<Item = Result<K>> + '_ {
160 self.inner.keys_range(..)
161 }
162 /// Traverse bounded keys without reading external value records.
163 ///
164 /// Routing records and key codecs remain checked. External value integrity
165 /// is checked only by operations that request values.
166 pub fn keys_range(
167 &self,
168 bounds: impl RangeBounds<K>,
169 ) -> impl DoubleEndedIterator<Item = Result<K>> + '_ {
170 self.inner.keys_range(bounds)
171 }
172 /// Perform `values` on the governed ordered map.
173 pub fn values(&self) -> impl DoubleEndedIterator<Item = Result<V>> + '_ {
174 self.iter().map(|entry| entry?.into_value())
175 }
176}
177
178impl<'a, K: Storable + Ord + Clone, V: Storable, M: Memory> IntoIterator
179 for &'a StableBTreeMap<K, V, M>
180{
181 type Item = <MapIter<'a, K, V, M> as Iterator>::Item;
182 type IntoIter = MapIter<'a, K, V, M>;
183 fn into_iter(self) -> Self::IntoIter {
184 self.iter()
185 }
186}