use super::bridge::{self, Backing, Codec};
use super::error::{CollectionError as Error, Result, ensure};
use super::{MapIter, Memory, Storable};
use crate::{DefaultMemoryImpl, RuntimeMemory};
use std::ops::RangeBounds;
pub struct StableBTreeMap<K: Storable + Ord + Clone, V: Storable, M: Memory = DefaultMemoryImpl> {
inner: bridge::Map<K, V, RuntimeMemory<M>>,
}
impl<K: Storable + Ord + Clone, V: Storable, M: Memory> StableBTreeMap<K, V, M> {
pub fn create(memory: RuntimeMemory<M>) -> Result<Self> {
ensure(memory.size() == 0, Error::NotEmpty)?;
Self::reset(memory)
}
pub fn reset(memory: RuntimeMemory<M>) -> Result<Self> {
bridge::reserve(&memory)?;
#[cfg(not(target_arch = "wasm32"))]
let _guard = memory.poison_on_unwind();
Ok(Self {
inner: bridge::Map::new(Backing(memory)),
})
}
pub fn load(memory: RuntimeMemory<M>) -> Result<Self> {
bridge::admit_map(&memory)?;
Ok(Self {
inner: bridge::Map::load(Backing(memory)),
})
}
pub fn clear(&mut self) -> Result<()> {
#[cfg(not(target_arch = "wasm32"))]
let _guard = self.inner.memory().0.poison_on_unwind();
self.inner.clear_new();
Ok(())
}
pub const fn set_node_cache_budget(&mut self, _bytes: usize) {
let _ = &self.inner;
}
pub fn reserve_pages(
self,
minimum: u64,
) -> (Self, std::result::Result<(), crate::RuntimeGrowError>) {
let additional = minimum.saturating_sub(self.inner.memory().0.size());
let result = self.inner.memory().0.grow(additional).map(|_| ());
(self, result)
}
#[must_use]
pub fn allocated_pages(self) -> (Self, u64) {
let pages = self.inner.memory().0.size();
(self, pages)
}
pub fn insert(&mut self, key: K, value: V) -> Result<Option<V>> {
#[cfg(not(target_arch = "wasm32"))]
let _guard = self.inner.memory().0.poison_on_unwind();
Ok(self.inner.insert(Codec(key), Codec(value)).map(|v| v.0))
}
pub fn get(&self, key: &K) -> Result<Option<V>> {
Ok(self.inner.get(Codec::borrowed(key)).map(|v| v.0))
}
pub fn contains_key(&self, key: &K) -> Result<bool> {
Ok(self.inner.contains_key(Codec::borrowed(key)))
}
#[must_use]
pub const fn is_empty(&self) -> bool {
self.inner.is_empty()
}
#[must_use]
pub const fn len(&self) -> u64 {
self.inner.len()
}
pub fn remove(&mut self, key: &K) -> Result<Option<V>> {
#[cfg(not(target_arch = "wasm32"))]
let _guard = self.inner.memory().0.poison_on_unwind();
Ok(self.inner.remove(Codec::borrowed(key)).map(|v| v.0))
}
pub fn first_key_value(&self) -> Result<Option<(K, V)>> {
Ok(self.inner.first_key_value().map(|(k, v)| (k.0, v.0)))
}
pub fn last_key_value(&self) -> Result<Option<(K, V)>> {
Ok(self.inner.last_key_value().map(|(k, v)| (k.0, v.0)))
}
#[must_use]
pub fn iter(&self) -> MapIter<'_, K, V, M> {
MapIter(self.inner.iter())
}
pub fn range(&self, bounds: impl RangeBounds<K>) -> MapIter<'_, K, V, M> {
MapIter(self.inner.range(codec_bounds(&bounds)))
}
pub fn keys(&self) -> impl DoubleEndedIterator<Item = Result<K>> + '_ {
self.inner.keys().map(|k| Ok(k.0))
}
pub fn keys_range(
&self,
bounds: impl RangeBounds<K>,
) -> impl DoubleEndedIterator<Item = Result<K>> + '_ {
self.inner
.keys_range(codec_bounds(&bounds))
.map(|k| Ok(k.0))
}
pub fn values(&self) -> impl DoubleEndedIterator<Item = Result<V>> + '_ {
self.inner.values().map(|v| Ok(v.0))
}
}
pub(super) fn codec_bounds<K: Clone>(
range: &impl RangeBounds<K>,
) -> (std::ops::Bound<Codec<K>>, std::ops::Bound<Codec<K>>) {
(
range.start_bound().map(|k| Codec(k.clone())),
range.end_bound().map(|k| Codec(k.clone())),
)
}
impl<'a, K: Storable + Ord + Clone, V: Storable, M: Memory> IntoIterator
for &'a StableBTreeMap<K, V, M>
{
type Item = <MapIter<'a, K, V, M> as Iterator>::Item;
type IntoIter = MapIter<'a, K, V, M>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}