Skip to main content

ic_storage/adapter/
map.rs

1//! Governed map operations over the copied ICSS B-tree.
2use super::bridge::{self, Backing, Codec};
3use super::error::{CollectionError as Error, Result, ensure};
4use super::{MapIter, Memory, Storable};
5use crate::{DefaultMemoryImpl, RuntimeMemory};
6use std::ops::RangeBounds;
7
8///
9/// `StableBTreeMap`
10///
11/// ICSS-baseline ordered map owning one governed allocation. Stored codec and
12/// engine failures trap. Native callers must discard the runtime after a mutation panic.
13///
14pub struct StableBTreeMap<K: Storable + Ord + Clone, V: Storable, M: Memory = DefaultMemoryImpl> {
15    inner: bridge::Map<K, V, RuntimeMemory<M>>,
16}
17impl<K: Storable + Ord + Clone, V: Storable, M: Memory> StableBTreeMap<K, V, M> {
18    /// Create only in empty admitted memory.
19    /// # Errors
20    /// Refuses nonempty memory or initial growth refusal.
21    pub fn create(memory: RuntimeMemory<M>) -> Result<Self> {
22        ensure(memory.size() == 0, Error::NotEmpty)?;
23        Self::reset(memory)
24    }
25    /// Explicitly replace this allocation's collection image.
26    /// # Errors
27    /// Refuses initial growth before creating the map.
28    pub fn reset(memory: RuntimeMemory<M>) -> Result<Self> {
29        bridge::reserve(&memory)?;
30        #[cfg(not(target_arch = "wasm32"))]
31        let _guard = memory.poison_on_unwind();
32        Ok(Self {
33            inner: bridge::Map::new(Backing(memory)),
34        })
35    }
36    /// Load the current BTR version without initialization or migration.
37    /// # Errors
38    /// Refuses empty or foreign framing.
39    pub fn load(memory: RuntimeMemory<M>) -> Result<Self> {
40        bridge::admit_map(&memory)?;
41        Ok(Self {
42            inner: bridge::Map::load(Backing(memory)),
43        })
44    }
45    /// Clear entries and reuse the map's existing backing capacity.
46    /// # Errors
47    /// Engine failures trap instead of returning an ordinary error.
48    pub fn clear(&mut self) -> Result<()> {
49        #[cfg(not(target_arch = "wasm32"))]
50        let _guard = self.inner.memory().0.poison_on_unwind();
51        self.inner.clear_new();
52        Ok(())
53    }
54    /// Bound routing-cache memory. The baseline engine caches no routing nodes,
55    /// so every supplied ceiling is satisfied with zero cached bytes.
56    pub const fn set_node_cache_budget(&mut self, _bytes: usize) {
57        let _ = &self.inner;
58    }
59    /// Reserve backing pages without promising entry capacity.
60    pub fn reserve_pages(
61        self,
62        minimum: u64,
63    ) -> (Self, std::result::Result<(), crate::RuntimeGrowError>) {
64        let additional = minimum.saturating_sub(self.inner.memory().0.size());
65        let result = self.inner.memory().0.grow(additional).map(|_| ());
66        (self, result)
67    }
68    /// Observe allocated pages while retaining exclusive custody.
69    #[must_use]
70    pub fn allocated_pages(self) -> (Self, u64) {
71        let pages = self.inner.memory().0.size();
72        (self, pages)
73    }
74    /// Insert or replace. Invalid codecs and allocation failures trap.
75    /// # Errors
76    /// Engine failures trap instead of returning an ordinary error.
77    pub fn insert(&mut self, key: K, value: V) -> Result<Option<V>> {
78        #[cfg(not(target_arch = "wasm32"))]
79        let _guard = self.inner.memory().0.poison_on_unwind();
80        Ok(self.inner.insert(Codec(key), Codec(value)).map(|v| v.0))
81    }
82    /// Read a matching value; malformed stored values trap.
83    /// # Errors
84    /// Engine failures trap instead of returning an ordinary error.
85    pub fn get(&self, key: &K) -> Result<Option<V>> {
86        Ok(self.inner.get(Codec::borrowed(key)).map(|v| v.0))
87    }
88    /// Test key membership without decoding values.
89    /// # Errors
90    /// Engine failures trap instead of returning an ordinary error.
91    pub fn contains_key(&self, key: &K) -> Result<bool> {
92        Ok(self.inner.contains_key(Codec::borrowed(key)))
93    }
94    /// Whether no entries are committed.
95    #[must_use]
96    pub const fn is_empty(&self) -> bool {
97        self.inner.is_empty()
98    }
99    /// Number of entries.
100    #[must_use]
101    pub const fn len(&self) -> u64 {
102        self.inner.len()
103    }
104    /// Remove a matching value; codec and engine failures trap.
105    /// # Errors
106    /// Engine failures trap instead of returning an ordinary error.
107    pub fn remove(&mut self, key: &K) -> Result<Option<V>> {
108        #[cfg(not(target_arch = "wasm32"))]
109        let _guard = self.inner.memory().0.poison_on_unwind();
110        Ok(self.inner.remove(Codec::borrowed(key)).map(|v| v.0))
111    }
112    /// First ordered key/value pair.
113    /// # Errors
114    /// Engine failures trap instead of returning an ordinary error.
115    pub fn first_key_value(&self) -> Result<Option<(K, V)>> {
116        Ok(self.inner.first_key_value().map(|(k, v)| (k.0, v.0)))
117    }
118    /// Last ordered key/value pair.
119    /// # Errors
120    /// Engine failures trap instead of returning an ordinary error.
121    pub fn last_key_value(&self) -> Result<Option<(K, V)>> {
122        Ok(self.inner.last_key_value().map(|(k, v)| (k.0, v.0)))
123    }
124    /// Iterate in key order.
125    #[must_use]
126    pub fn iter(&self) -> MapIter<'_, K, V, M> {
127        MapIter(self.inner.iter())
128    }
129    /// Iterate a bounded key range.
130    pub fn range(&self, bounds: impl RangeBounds<K>) -> MapIter<'_, K, V, M> {
131        MapIter(self.inner.range(codec_bounds(&bounds)))
132    }
133    /// Iterate keys without reading value payloads.
134    pub fn keys(&self) -> impl DoubleEndedIterator<Item = Result<K>> + '_ {
135        self.inner.keys().map(|k| Ok(k.0))
136    }
137    /// Iterate bounded keys without reading value payloads.
138    pub fn keys_range(
139        &self,
140        bounds: impl RangeBounds<K>,
141    ) -> impl DoubleEndedIterator<Item = Result<K>> + '_ {
142        self.inner
143            .keys_range(codec_bounds(&bounds))
144            .map(|k| Ok(k.0))
145    }
146    /// Iterate decoded values.
147    pub fn values(&self) -> impl DoubleEndedIterator<Item = Result<V>> + '_ {
148        self.inner.values().map(|v| Ok(v.0))
149    }
150}
151
152pub(super) fn codec_bounds<K: Clone>(
153    range: &impl RangeBounds<K>,
154) -> (std::ops::Bound<Codec<K>>, std::ops::Bound<Codec<K>>) {
155    (
156        range.start_bound().map(|k| Codec(k.clone())),
157        range.end_bound().map(|k| Codec(k.clone())),
158    )
159}
160impl<'a, K: Storable + Ord + Clone, V: Storable, M: Memory> IntoIterator
161    for &'a StableBTreeMap<K, V, M>
162{
163    type Item = <MapIter<'a, K, V, M> as Iterator>::Item;
164    type IntoIter = MapIter<'a, K, V, M>;
165    fn into_iter(self) -> Self::IntoIter {
166        self.iter()
167    }
168}