Skip to main content

noether_store/
traits.rs

1use noether_core::stage::{Stage, StageId, StageLifecycle};
2use std::collections::BTreeMap;
3
4#[derive(Debug, thiserror::Error)]
5pub enum StoreError {
6    #[error("stage with id {0:?} already exists")]
7    AlreadyExists(StageId),
8    #[error("stage with id {0:?} not found")]
9    NotFound(StageId),
10    #[error("invalid lifecycle transition: {reason}")]
11    InvalidTransition { reason: String },
12    #[error("invalid successor: {reason}")]
13    InvalidSuccessor { reason: String },
14    #[error("validation failed: {0:?}")]
15    ValidationFailed(Vec<String>),
16    #[error("I/O error: {message}")]
17    IoError { message: String },
18}
19
20/// Summary statistics for a store.
21#[derive(Debug, Clone)]
22pub struct StoreStats {
23    pub total: usize,
24    pub by_lifecycle: BTreeMap<String, usize>,
25    pub by_effect: BTreeMap<String, usize>,
26}
27
28/// Abstraction over stage storage.
29pub trait StageStore {
30    fn put(&mut self, stage: Stage) -> Result<StageId, StoreError>;
31    /// Insert a stage, replacing any existing stage with the same ID.
32    /// Used to upgrade unsigned stdlib stages after signing is added.
33    fn upsert(&mut self, stage: Stage) -> Result<StageId, StoreError>;
34    /// Remove a stage entirely. Returns `Ok(())` whether or not the stage existed.
35    fn remove(&mut self, id: &StageId) -> Result<(), StoreError>;
36    fn get(&self, id: &StageId) -> Result<Option<&Stage>, StoreError>;
37    fn contains(&self, id: &StageId) -> bool;
38    fn list(&self, lifecycle: Option<&StageLifecycle>) -> Vec<&Stage>;
39    fn update_lifecycle(
40        &mut self,
41        id: &StageId,
42        lifecycle: StageLifecycle,
43    ) -> Result<(), StoreError>;
44    fn stats(&self) -> StoreStats;
45
46    // ── Owned accessors (default impls — no need to override) ──────────────
47
48    /// Return an owned clone of the stage. Useful for async contexts where
49    /// holding a borrow across lock boundaries is not permitted.
50    fn get_owned(&self, id: &StageId) -> Result<Option<Stage>, StoreError> {
51        Ok(self.get(id)?.cloned())
52    }
53
54    /// Return owned clones of all matching stages.
55    fn list_owned(&self, lifecycle: Option<&StageLifecycle>) -> Vec<Stage> {
56        self.list(lifecycle).into_iter().cloned().collect()
57    }
58}