use crate::substrate::{self, DefaultMemoryImpl};
use ic_memory::RuntimeMemory;
use std::{borrow::Cow, ops::RangeBounds};
pub use substrate::{Memory, Storable, storable, storable::Bound};
#[cfg(all(test, not(target_arch = "wasm32")))]
mod tests;
mod region;
pub use region::{BTreeMapRegion, RegionGrowError};
pub struct StableBTreeMap<K: Storable + Ord + Clone, V: Storable, M: Memory = DefaultMemoryImpl> {
inner: substrate::BTreeMap<K, V, RuntimeMemory<M>>,
}
impl<K: Storable + Ord + Clone, V: Storable, M: Memory> StableBTreeMap<K, V, M> {
pub fn new(memory: RuntimeMemory<M>) -> Self {
Self {
inner: substrate::BTreeMap::new(memory),
}
}
pub fn init(memory: RuntimeMemory<M>) -> Self {
Self {
inner: substrate::BTreeMap::init(memory),
}
}
pub fn load(memory: RuntimeMemory<M>) -> Self {
Self {
inner: substrate::BTreeMap::load(memory),
}
}
pub fn clear(&mut self) {
self.inner.clear_new();
}
pub fn reserve_pages(self, minimum: u64) -> (Self, Result<(), ic_memory::RuntimeGrowError>) {
let memory = self.inner.into_memory();
let additional = minimum.saturating_sub(memory.size());
let result = memory.grow(additional).map(|_| ());
(Self::load(memory), result)
}
#[must_use]
pub fn allocated_pages(self) -> (Self, u64) {
let memory = self.inner.into_memory();
let pages = memory.size();
(Self::load(memory), pages)
}
pub fn insert(&mut self, key: K, value: V) -> Option<V> {
self.inner.insert(key, value)
}
pub fn get(&self, key: &K) -> Option<V> {
self.inner.get(key)
}
pub fn contains_key(&self, key: &K) -> bool {
self.inner.contains_key(key)
}
pub fn is_empty(&self) -> bool {
self.inner.is_empty()
}
pub fn len(&self) -> u64 {
self.inner.len()
}
pub fn remove(&mut self, key: &K) -> Option<V> {
self.inner.remove(key)
}
pub fn first_key_value(&self) -> Option<(K, V)> {
self.inner.first_key_value()
}
pub fn last_key_value(&self) -> Option<(K, V)> {
self.inner.last_key_value()
}
pub fn pop_first(&mut self) -> Option<(K, V)> {
self.inner.pop_first()
}
pub fn pop_last(&mut self) -> Option<(K, V)> {
self.inner.pop_last()
}
pub fn iter(&self) -> MapIter<'_, K, V, M> {
self.inner.iter()
}
pub fn range(&self, key_range: impl RangeBounds<K>) -> MapIter<'_, K, V, M> {
self.inner.range(key_range)
}
pub fn keys(&self) -> impl DoubleEndedIterator<Item = K> + '_ {
self.inner.keys()
}
pub fn values(&self) -> impl DoubleEndedIterator<Item = V> + '_ {
self.inner.values()
}
}
pub struct StableBTreeSet<K: Storable + Ord + Clone, M: Memory = DefaultMemoryImpl> {
inner: substrate::BTreeSet<K, RuntimeMemory<M>>,
}
impl<K: Storable + Ord + Clone, M: Memory> StableBTreeSet<K, M> {
pub fn new(memory: RuntimeMemory<M>) -> Self {
Self {
inner: substrate::BTreeSet::new(memory),
}
}
pub fn init(memory: RuntimeMemory<M>) -> Self {
Self {
inner: substrate::BTreeSet::init(memory),
}
}
pub fn load(memory: RuntimeMemory<M>) -> Self {
Self {
inner: substrate::BTreeSet::load(memory),
}
}
pub fn insert(&mut self, key: K) -> bool {
self.inner.insert(key)
}
pub fn contains(&self, key: &K) -> bool {
self.inner.contains(key)
}
pub fn is_empty(&self) -> bool {
self.inner.is_empty()
}
pub fn len(&self) -> u64 {
self.inner.len()
}
pub fn remove(&mut self, key: &K) -> bool {
self.inner.remove(key)
}
pub fn first(&self) -> Option<K> {
self.inner.first()
}
pub fn last(&self) -> Option<K> {
self.inner.last()
}
pub fn pop_first(&mut self) -> Option<K> {
self.inner.pop_first()
}
pub fn pop_last(&mut self) -> Option<K> {
self.inner.pop_last()
}
pub fn iter(&self) -> SetIter<'_, K, M> {
self.inner.iter()
}
pub fn range(&self, key_range: impl RangeBounds<K>) -> SetIter<'_, K, M> {
self.inner.range(key_range)
}
pub fn clear(&mut self) {
self.inner.clear();
}
}
pub struct StableCell<T: Storable, M: Memory = DefaultMemoryImpl> {
inner: substrate::Cell<T, RuntimeMemory<M>>,
}
impl<T: Storable, M: Memory> StableCell<T, M> {
pub fn new(memory: RuntimeMemory<M>, value: T) -> Self {
Self {
inner: substrate::Cell::new(memory, value),
}
}
pub fn init(memory: RuntimeMemory<M>, default_value: T) -> Self {
Self {
inner: substrate::Cell::init(memory, default_value),
}
}
pub fn get(&self) -> &T {
self.inner.get()
}
pub fn set(&mut self, value: T) -> T {
self.inner.set(value)
}
}
pub struct StableVec<T: Storable, M: Memory = DefaultMemoryImpl> {
inner: substrate::Vec<T, RuntimeMemory<M>>,
}
impl<T: Storable, M: Memory> StableVec<T, M> {
pub fn new(memory: RuntimeMemory<M>) -> Self {
Self {
inner: substrate::Vec::new(memory),
}
}
pub fn init(memory: RuntimeMemory<M>) -> Self {
Self {
inner: substrate::Vec::init(memory),
}
}
pub fn get(&self, index: u64) -> Option<T> {
self.inner.get(index)
}
pub fn set(&self, index: u64, item: &T) {
self.inner.set(index, item);
}
pub fn push(&self, item: &T) {
self.inner.push(item);
}
pub fn pop(&self) -> Option<T> {
self.inner.pop()
}
#[must_use]
pub fn reset(self) -> Self {
Self::new(self.inner.into_memory())
}
pub fn len(&self) -> u64 {
self.inner.len()
}
pub fn is_empty(&self) -> bool {
self.inner.is_empty()
}
pub fn iter(&self) -> impl DoubleEndedIterator<Item = T> + '_ {
self.inner.iter()
}
}
pub struct StableMinHeap<T: Storable + Ord, M: Memory = DefaultMemoryImpl> {
inner: substrate::MinHeap<T, RuntimeMemory<M>>,
}
impl<T: Storable + Ord, M: Memory> StableMinHeap<T, M> {
pub fn new(memory: RuntimeMemory<M>) -> Self {
Self {
inner: substrate::MinHeap::new(memory),
}
}
pub fn init(memory: RuntimeMemory<M>) -> Self {
Self {
inner: substrate::MinHeap::init(memory),
}
}
pub fn push(&mut self, item: &T) {
self.inner.push(item);
}
pub fn pop(&mut self) -> Option<T> {
self.inner.pop()
}
pub fn peek(&self) -> Option<T> {
self.inner.peek()
}
pub fn len(&self) -> u64 {
self.inner.len()
}
pub fn is_empty(&self) -> bool {
self.inner.is_empty()
}
pub fn iter(&self) -> impl Iterator<Item = T> + '_ {
self.inner.iter()
}
}
pub struct StableLog<T: Storable, M: Memory = DefaultMemoryImpl> {
inner: substrate::Log<T, RuntimeMemory<M>, RuntimeMemory<M>>,
}
impl<T: Storable, M: Memory> StableLog<T, M> {
pub fn new(index_memory: RuntimeMemory<M>, data_memory: RuntimeMemory<M>) -> Self {
Self {
inner: substrate::Log::new(index_memory, data_memory),
}
}
pub fn init(index_memory: RuntimeMemory<M>, data_memory: RuntimeMemory<M>) -> Self {
Self {
inner: substrate::Log::init(index_memory, data_memory),
}
}
pub fn first(&self) -> Option<T> {
self.inner.first()
}
pub fn last(&self) -> Option<T> {
self.inner.last()
}
pub fn get(&self, idx: u64) -> Option<T> {
self.inner.get(idx)
}
pub fn len(&self) -> u64 {
self.inner.len()
}
pub fn is_empty(&self) -> bool {
self.inner.is_empty()
}
pub fn append(&self, item: &T) -> Result<u64, LogWriteError> {
self.inner.append(item)
}
pub fn iter(&self) -> LogIter<'_, T, M> {
self.inner.iter()
}
}
pub type MapIter<'a, K, V, M = DefaultMemoryImpl> =
substrate::btreemap::Iter<'a, K, V, RuntimeMemory<M>>;
pub type SetIter<'a, K, M = DefaultMemoryImpl> = substrate::btreeset::Iter<'a, K, RuntimeMemory<M>>;
pub type LogIter<'a, T, M = DefaultMemoryImpl> =
substrate::log::Iter<'a, T, RuntimeMemory<M>, RuntimeMemory<M>>;
pub use substrate::log::WriteError as LogWriteError;
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()
}
}
impl<'a, K: Storable + Ord + Clone, M: Memory> IntoIterator for &'a StableBTreeSet<K, M> {
type Item = K;
type IntoIter = SetIter<'a, K, M>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<'a, T: Storable, M: Memory> IntoIterator for &'a StableLog<T, M> {
type Item = T;
type IntoIter = LogIter<'a, T, M>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
pub struct BoundedCell<T: Storable, M: Memory = DefaultMemoryImpl> {
cell: substrate::Cell<BoundedValue<T>, RuntimeMemory<M>>,
}
impl<T: Storable, M: Memory> BoundedCell<T, M> {
#[must_use]
pub fn init(memory: RuntimeMemory<M>, value: T) -> Self {
assert!(matches!(T::BOUND, Bound::Bounded { .. }));
Self {
cell: substrate::Cell::init(memory, BoundedValue(value)),
}
}
#[must_use]
pub fn get(&self) -> &T {
&self.cell.get().0
}
pub fn set(&mut self, value: T) -> T {
self.cell.set(BoundedValue(value)).0
}
}
struct BoundedValue<T>(T);
impl<T: Storable> Storable for BoundedValue<T> {
const BOUND: Bound = T::BOUND;
fn to_bytes(&self) -> Cow<'_, [u8]> {
self.0.to_bytes_checked()
}
fn into_bytes(self) -> Vec<u8> {
self.0.into_bytes_checked()
}
fn from_bytes(bytes: Cow<'_, [u8]>) -> Self {
let Bound::Bounded {
max_size,
is_fixed_size,
} = T::BOUND
else {
unreachable!("bounded cell record must declare a bound");
};
if is_fixed_size {
assert_eq!(bytes.len(), max_size as usize);
} else {
assert!(bytes.len() <= max_size as usize);
}
Self(T::from_bytes(bytes))
}
}