manifoldb_storage/engine/
error.rs

1//! Storage error types.
2//!
3//! This module defines the error types for storage operations. All errors
4//! implement [`std::error::Error`] and provide descriptive messages.
5
6use std::fmt;
7
8use thiserror::Error;
9
10/// Errors that can occur in storage operations.
11///
12/// This enum covers all possible failure modes for storage backends,
13/// from database-level issues to transaction and I/O errors.
14#[derive(Debug, Error)]
15pub enum StorageError {
16    /// The database could not be opened or created.
17    #[error("failed to open database: {0}")]
18    Open(String),
19
20    /// The database file or directory does not exist.
21    #[error("database not found: {0}")]
22    NotFound(String),
23
24    /// A table does not exist.
25    #[error("table not found: {0}")]
26    TableNotFound(String),
27
28    /// A key was not found in the table.
29    #[error("key not found")]
30    KeyNotFound,
31
32    /// A transaction error occurred (failed to begin, commit, or rollback).
33    #[error("transaction error: {0}")]
34    Transaction(String),
35
36    /// Attempted a write operation on a read-only transaction.
37    #[error("cannot write in read-only transaction")]
38    ReadOnly,
39
40    /// A conflict occurred due to concurrent modification.
41    #[error("write conflict: {0}")]
42    Conflict(String),
43
44    /// The database is corrupted.
45    #[error("database corruption detected: {0}")]
46    Corruption(String),
47
48    /// An I/O error occurred.
49    #[error("I/O error: {0}")]
50    Io(#[from] std::io::Error),
51
52    /// A serialization or deserialization error occurred.
53    #[error("serialization error: {0}")]
54    Serialization(String),
55
56    /// The storage is full or a size limit was exceeded.
57    #[error("storage full: {0}")]
58    StorageFull(String),
59
60    /// An invalid argument was provided.
61    #[error("invalid argument: {0}")]
62    InvalidArgument(String),
63
64    /// The operation is not supported by this backend.
65    #[error("operation not supported: {0}")]
66    Unsupported(String),
67
68    /// An internal error occurred in the storage backend.
69    #[error("internal error: {0}")]
70    Internal(String),
71}
72
73impl StorageError {
74    /// Returns `true` if this error is recoverable.
75    ///
76    /// Recoverable errors include transient conditions like conflicts
77    /// that may succeed on retry. Non-recoverable errors include
78    /// corruption and configuration issues.
79    #[must_use]
80    pub const fn is_recoverable(&self) -> bool {
81        matches!(self, Self::Conflict(_) | Self::Transaction(_) | Self::Io(_))
82    }
83
84    /// Returns `true` if this is a "not found" type error.
85    #[must_use]
86    pub const fn is_not_found(&self) -> bool {
87        matches!(self, Self::NotFound(_) | Self::TableNotFound(_) | Self::KeyNotFound)
88    }
89}
90
91/// Result type alias for storage operations.
92pub type StorageResult<T> = Result<T, StorageError>;
93
94/// Additional context for storage errors.
95#[derive(Debug)]
96pub struct ErrorContext {
97    /// The table involved in the error, if any.
98    pub table: Option<String>,
99    /// The key involved in the error, if any (as hex string).
100    pub key: Option<String>,
101    /// Additional context message.
102    pub message: Option<String>,
103}
104
105impl fmt::Display for ErrorContext {
106    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
107        let mut parts = Vec::new();
108        if let Some(ref table) = self.table {
109            parts.push(format!("table={table}"));
110        }
111        if let Some(ref key) = self.key {
112            parts.push(format!("key={key}"));
113        }
114        if let Some(ref msg) = self.message {
115            parts.push(msg.clone());
116        }
117        write!(f, "{}", parts.join(", "))
118    }
119}