Skip to main content

ic_storage/adapter/
cell.rs

1//! Governed cached cell over the copied ICSS cell engine.
2use super::{
3    Bound, Memory, Storable,
4    bridge::{self, Backing, Codec},
5    error::{CollectionError as Error, Result, ensure},
6};
7use crate::{DefaultMemoryImpl, RuntimeMemory, engine};
8
9///
10/// `StableCell`
11///
12/// ICSS-baseline single cached value with explicit non-initializing admission.
13/// Stored values have no checksum. Malformed application records trap.
14///
15pub struct StableCell<T: Storable, M: Memory = DefaultMemoryImpl> {
16    inner: engine::cell::Cell<Codec<T>, Backing<RuntimeMemory<M>>>,
17}
18impl<T: Storable, M: Memory> StableCell<T, M> {
19    /// Create only in empty admitted memory.
20    /// # Errors
21    /// Refuses nonempty memory or initial growth refusal.
22    pub fn create(memory: RuntimeMemory<M>, value: T) -> Result<Self> {
23        ensure(memory.size() == 0, Error::NotEmpty)?;
24        Self::reset(memory, value)
25    }
26    /// Explicitly replace the cell image.
27    /// # Errors
28    /// Refuses initial growth; codec/engine failures trap.
29    pub fn reset(memory: RuntimeMemory<M>, value: T) -> Result<Self> {
30        bridge::reserve(&memory)?;
31        #[cfg(not(target_arch = "wasm32"))]
32        let _guard = memory.poison_on_unwind();
33        Ok(Self {
34            inner: engine::cell::Cell::new(Backing(memory), Codec(value)),
35        })
36    }
37    /// Load without initializing. Admit the payload ceiling before allocation.
38    /// # Errors
39    /// Refuses invalid framing or an exceeded ceiling; malformed values trap.
40    /// # Panics
41    /// Stored codec failures propagate as traps.
42    pub fn load(memory: RuntimeMemory<M>, maximum: usize) -> Result<Self> {
43        let maximum = match T::BOUND {
44            Bound::Bounded { max_size, .. } => maximum.min(max_size as usize),
45            Bound::Unbounded => maximum,
46        };
47        let length = crate::stable_cell_payload_length(&memory, maximum)?;
48        Ok(Self {
49            inner: engine::cell::Cell::load_with_length(
50                Backing(memory),
51                u32::try_from(length).expect("admitted cell length"),
52            ),
53        })
54    }
55    /// Borrow the cached value without IO.
56    pub const fn get(&self) -> &T {
57        &self.inner.get().0
58    }
59    /// Persist a replacement and return the old value. Failures trap.
60    /// # Errors
61    /// Engine failures trap instead of returning an ordinary error.
62    pub fn set(&mut self, value: T) -> Result<T> {
63        #[cfg(not(target_arch = "wasm32"))]
64        let _guard = self.inner.memory().0.poison_on_unwind();
65        Ok(self.inner.set(Codec(value)).0)
66    }
67}