use super::{
Bound, Memory, Storable,
bridge::{self, Backing, Codec},
error::{CollectionError as Error, Result, ensure},
};
use crate::{DefaultMemoryImpl, RuntimeMemory, engine};
pub struct StableCell<T: Storable, M: Memory = DefaultMemoryImpl> {
inner: engine::cell::Cell<Codec<T>, Backing<RuntimeMemory<M>>>,
}
impl<T: Storable, M: Memory> StableCell<T, M> {
pub fn create(memory: RuntimeMemory<M>, value: T) -> Result<Self> {
ensure(memory.size() == 0, Error::NotEmpty)?;
Self::reset(memory, value)
}
pub fn reset(memory: RuntimeMemory<M>, value: T) -> Result<Self> {
bridge::reserve(&memory)?;
#[cfg(not(target_arch = "wasm32"))]
let _guard = memory.poison_on_unwind();
Ok(Self {
inner: engine::cell::Cell::new(Backing(memory), Codec(value)),
})
}
pub fn load(memory: RuntimeMemory<M>, maximum: usize) -> Result<Self> {
let maximum = match T::BOUND {
Bound::Bounded { max_size, .. } => maximum.min(max_size as usize),
Bound::Unbounded => maximum,
};
let length = crate::stable_cell_payload_length(&memory, maximum)?;
Ok(Self {
inner: engine::cell::Cell::load_with_length(
Backing(memory),
u32::try_from(length).expect("admitted cell length"),
),
})
}
pub const fn get(&self) -> &T {
&self.inner.get().0
}
pub fn set(&mut self, value: T) -> Result<T> {
#[cfg(not(target_arch = "wasm32"))]
let _guard = self.inner.memory().0.poison_on_unwind();
Ok(self.inner.set(Codec(value)).0)
}
}