Skip to main content

relay_knowledge/storage/contracts/
boundary.rs

1use std::{error::Error, fmt, future::Future, pin::Pin};
2
3pub type StorageFuture<'a, T> = Pin<Box<dyn Future<Output = Result<T, StorageError>> + Send + 'a>>;
4
5/// Storage boundary failure.
6#[derive(Debug)]
7pub enum StorageError {
8    Io(std::io::Error),
9    Sqlite(rusqlite::Error),
10    Join(tokio::task::JoinError),
11    LockPoisoned,
12    Busy(String),
13    CapacityExceeded(String),
14    DurableStagingRequired(String),
15    DurableStagingPending {
16        completed_steps: usize,
17        max_steps: usize,
18    },
19    DurableFinalizationRequired {
20        checkpoint_state: String,
21    },
22    InvalidInput(String),
23    Invariant(String),
24}
25
26impl fmt::Display for StorageError {
27    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
28        match self {
29            Self::Io(error) => write!(formatter, "storage I/O failed: {error}"),
30            Self::Sqlite(error) => write!(formatter, "sqlite operation failed: {error}"),
31            Self::Join(error) => write!(formatter, "storage worker failed: {error}"),
32            Self::LockPoisoned => write!(formatter, "sqlite connection lock was poisoned"),
33            Self::Busy(message) => write!(formatter, "storage busy: {message}"),
34            Self::CapacityExceeded(message) => {
35                write!(formatter, "storage capacity exceeded: {message}")
36            }
37            Self::DurableStagingRequired(message) => {
38                write!(formatter, "durable staging required: {message}")
39            }
40            Self::DurableStagingPending {
41                completed_steps,
42                max_steps,
43            } => write!(
44                formatter,
45                "durable staging pending after step {completed_steps} of at most {max_steps}"
46            ),
47            Self::DurableFinalizationRequired { checkpoint_state } => write!(
48                formatter,
49                "durable incremental delta committed; finalization must resume from '{checkpoint_state}'"
50            ),
51            Self::InvalidInput(message) => write!(formatter, "invalid storage input: {message}"),
52            Self::Invariant(message) => write!(formatter, "storage invariant failed: {message}"),
53        }
54    }
55}
56
57impl Error for StorageError {}
58
59impl From<std::io::Error> for StorageError {
60    fn from(error: std::io::Error) -> Self {
61        Self::Io(error)
62    }
63}
64
65impl From<rusqlite::Error> for StorageError {
66    fn from(error: rusqlite::Error) -> Self {
67        Self::Sqlite(error)
68    }
69}
70
71impl From<tokio::task::JoinError> for StorageError {
72    fn from(error: tokio::task::JoinError) -> Self {
73        Self::Join(error)
74    }
75}
76
77#[cfg(test)]
78#[path = "boundary_tests.rs"]
79mod tests;