pub use crate::runtime::fixture_diagnostics::{
DiagnosticCheck, DiagnosticCode, DiagnosticFailure, DiagnosticRuntimeBinding,
DiagnosticStableCell, DiagnosticStableCellStatus, MemoryRuntimeDoctorReport, doctor_report,
};
mod sparse_image;
pub use sparse_image::{SparseMemoryImageError, memory_from_sparse_hex};
mod runtime;
pub use runtime::{FixtureRuntimeError, fixture_runtime};
use crate::{Memory, MemoryManagerConfig, RuntimeMemory};
use ic_stable_structures::Cell;
use crate::{
AllocationDeclaration, MemoryManagerSlot, MemoryManagerSlotError, StableKey, StableKeyError,
};
#[non_exhaustive]
#[derive(Clone, Debug, Eq, thiserror::Error, PartialEq)]
pub enum DeclarationSnapshotError {
#[error(transparent)]
Key(StableKeyError),
#[error(transparent)]
MemoryManagerSlot(MemoryManagerSlotError),
}
impl AllocationDeclaration {
pub fn new(
stable_key: impl AsRef<str>,
slot: MemoryManagerSlot,
) -> Result<Self, DeclarationSnapshotError> {
let stable_key = StableKey::parse(stable_key).map_err(DeclarationSnapshotError::Key)?;
Ok(Self { stable_key, slot })
}
pub fn memory_manager(
stable_key: impl AsRef<str>,
id: u8,
) -> Result<Self, DeclarationSnapshotError> {
let slot =
MemoryManagerSlot::new(id).map_err(DeclarationSnapshotError::MemoryManagerSlot)?;
Self::new(stable_key, slot)
}
}
pub use crate::ledger::{AllocationLedger, LedgerCommitStore};
pub use crate::stable_cell::{
decode_stable_cell_commit_store, decode_stable_cell_commit_store_from_memory,
};
#[must_use]
pub fn allocation_record(declaration: &crate::AllocationDeclaration) -> crate::AllocationRecord {
crate::AllocationRecord::from_declaration(declaration)
}
pub struct FixtureCell<M: Memory> {
cell: Cell<Vec<u8>, RuntimeMemory<M>>,
maximum: usize,
}
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum FixtureCellError {
#[error(transparent)]
Setup(#[from] FixtureRuntimeError),
#[error(transparent)]
Open(#[from] crate::RuntimeOpenError),
#[error(transparent)]
Payload(#[from] crate::StableCellPayloadError),
#[error("fixture allocation is already occupied")]
Occupied,
#[error("fixture value length {size} exceeds byte limit {maximum}")]
ValueTooLarge { size: usize, maximum: usize },
}
impl<M: Memory> FixtureCell<M> {
pub fn create_bounded(
memory: M,
owner: &str,
namespace: &str,
stable_key: &str,
config: MemoryManagerConfig,
maximum: usize,
) -> Result<Self, FixtureCellError> {
let memory = Self::open_memory(memory, owner, namespace, stable_key, config)?;
if memory.size() > 0 {
return Err(FixtureCellError::Occupied);
}
Ok(Self::from_admitted_memory(memory, maximum))
}
pub fn open_bounded(
memory: M,
owner: &str,
namespace: &str,
stable_key: &str,
config: MemoryManagerConfig,
maximum: usize,
) -> Result<Self, FixtureCellError> {
if memory.size() == 0 {
return Err(crate::StableCellPayloadError::NotStableCell.into());
}
let memory = Self::open_memory(memory, owner, namespace, stable_key, config)?;
crate::stable_cell::stable_cell_payload_length(&memory, maximum)?;
Ok(Self::from_admitted_memory(memory, maximum))
}
fn open_memory(
memory: M,
owner: &str,
namespace: &str,
stable_key: &str,
config: MemoryManagerConfig,
) -> Result<RuntimeMemory<M>, FixtureCellError> {
let runtime = fixture_runtime(memory, owner, namespace, &[stable_key], config)?;
Ok(runtime.open_memory(stable_key)?)
}
fn from_admitted_memory(memory: RuntimeMemory<M>, maximum: usize) -> Self {
Self {
cell: Cell::init(memory, Vec::new()),
maximum,
}
}
#[must_use]
pub fn into_memory(self) -> RuntimeMemory<M> {
self.cell.into_memory()
}
#[must_use]
pub fn bytes(&self) -> &[u8] {
self.cell.get()
}
pub fn try_set(&mut self, bytes: Vec<u8>) -> Result<(), FixtureCellError> {
if bytes.len() > self.maximum {
return Err(FixtureCellError::ValueTooLarge {
size: bytes.len(),
maximum: self.maximum,
});
}
self.cell.set(bytes);
Ok(())
}
}
#[cfg(test)]
mod tests;