#![allow(missing_docs)]
use crate::crossing::CrossingRecord;
use crate::ledger::LedgerEntry;
use crate::perspectival::PerspectivalEntry;
use crate::quad::Quad;
use crate::ring::Ring;
use crate::types::{Layer, UnitId};
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum RingStoreBackendError {
#[error("storage error: {0}")]
Storage(String),
#[error("concurrency error: {0}")]
Concurrency(String),
#[error("backend error: {0}")]
Other(String),
}
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum RingStoreError {
#[error("not found: {context}")]
NotFound { context: String },
#[error("integrity error: {context}")]
Integrity { context: String },
#[error("serialization error: {0}")]
Serialization(String),
#[error("backend error: {0}")]
Backend(RingStoreBackendError),
}
pub type RingStoreResult<T> = Result<T, RingStoreError>;
pub trait RingStore: Send + Sync {
fn initialize(&self) -> RingStoreResult<()>;
fn compact(&self) -> RingStoreResult<bool>;
fn persist_genesis(
&self,
ring: &Ring,
crossing_records: &[CrossingRecord],
ledger_entry: &LedgerEntry,
seed: &[u8],
boundary_verifying_key: &[u8; 32],
) -> RingStoreResult<()>;
fn persist_cycle(
&self,
ring: &Ring,
cycle_index: u64,
crossing_records: &[CrossingRecord],
ledger_entry: &LedgerEntry,
) -> RingStoreResult<()>;
fn persist_perspectival(
&self,
cycle_index: u64,
entries: &[(UnitId, PerspectivalEntry)],
cross_verification: &[u8; 32],
) -> RingStoreResult<()>;
fn latest_cycle(&self) -> RingStoreResult<Option<u64>>;
fn has_genesis(&self) -> RingStoreResult<bool>;
fn get_som_quad(&self, cycle_index: u64, unit: UnitId, layer: Layer) -> RingStoreResult<Quad>;
fn get_soma_quad(&self, cycle_index: u64, unit: UnitId) -> RingStoreResult<Quad>;
fn get_crossing_records(&self, cycle_index: u64) -> RingStoreResult<Vec<CrossingRecord>>;
fn get_ledger_entry(&self, cycle_index: u64) -> RingStoreResult<LedgerEntry>;
fn get_all_ledger_entries(&self) -> RingStoreResult<Vec<LedgerEntry>>;
fn get_genesis_seed(&self) -> RingStoreResult<Vec<u8>>;
fn get_boundary_key(&self) -> RingStoreResult<[u8; 32]>;
fn get_perspectival_entry(
&self,
cycle_index: u64,
unit: UnitId,
) -> RingStoreResult<PerspectivalEntry>;
fn get_perspectival_entries(
&self,
cycle_index: u64,
) -> RingStoreResult<Vec<(UnitId, PerspectivalEntry)>>;
fn get_unit_chain(&self, unit: UnitId) -> RingStoreResult<Vec<PerspectivalEntry>>;
fn get_cross_verification(&self, cycle_index: u64) -> RingStoreResult<[u8; 32]>;
fn get_all_cross_verifications(&self) -> RingStoreResult<Vec<(u64, [u8; 32])>>;
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn ring_store_is_object_safe() {
fn _assert_object_safe(_: &dyn RingStore) {}
}
#[test]
fn error_variants() {
let e = RingStoreError::NotFound {
context: "test".into(),
};
assert!(e.to_string().contains("not found"));
let e = RingStoreError::Integrity {
context: "bad".into(),
};
assert!(e.to_string().contains("integrity"));
let e = RingStoreError::Backend(RingStoreBackendError::Storage("disk full".into()));
assert!(e.to_string().contains("storage error"));
let e = RingStoreError::Backend(RingStoreBackendError::Concurrency("lock held".into()));
assert!(e.to_string().contains("concurrency error"));
}
#[test]
fn backend_error_pattern_match_drives_recovery() {
fn classify(e: &RingStoreError) -> &'static str {
match e {
RingStoreError::Backend(RingStoreBackendError::Storage(_)) => "retry-after-io",
RingStoreError::Backend(RingStoreBackendError::Concurrency(_)) => "retry-tx",
RingStoreError::Backend(RingStoreBackendError::Other(_)) => "escalate",
_ => "other",
}
}
assert_eq!(
classify(&RingStoreError::Backend(RingStoreBackendError::Storage("x".into()))),
"retry-after-io"
);
assert_eq!(
classify(&RingStoreError::Backend(RingStoreBackendError::Concurrency("x".into()))),
"retry-tx"
);
}
}