arb_storage_errors/
db.rs

1use alloc::{boxed::Box, string::String};
2use core::error::Error;
3
4use crate::AnyError;
5
6/// Errors surfaced by the underlying state database when arb-storage reads or
7/// writes a slot.
8///
9/// The underlying `Database::Error` is erased here so that callers do not
10/// have to propagate a generic `<DBErr>` parameter through every layer.
11#[derive(Clone, Debug, thiserror::Error)]
12pub enum DatabaseError {
13    /// The database returned an error while reading a slot.
14    #[error("failed to read storage slot: {0}")]
15    Read(DatabaseErrorInfo),
16
17    /// The database returned an error while writing a slot.
18    #[error("failed to write storage slot: {0}")]
19    Write(DatabaseErrorInfo),
20
21    /// Catch-all wrapper for implementation-specific errors that do not fit
22    /// `Read` or `Write`.
23    #[error(transparent)]
24    Custom(AnyError),
25}
26
27impl DatabaseError {
28    /// Wraps any [`Error`] as a [`DatabaseError::Custom`].
29    pub fn custom<E>(error: E) -> Self
30    where
31        E: Error + Send + Sync + 'static,
32    {
33        Self::Custom(AnyError::new(error))
34    }
35}
36
37/// Implementation-agnostic information about a database failure.
38///
39/// Stores only the rendered error message, since the concrete `Database::Error`
40/// type is erased at the leaf and there is no general way to extract a numeric
41/// code from it. Implementations that do carry a code can encode it into the
42/// message string.
43#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
44#[error("{message}")]
45pub struct DatabaseErrorInfo {
46    /// Human-readable error message rendered from the underlying database
47    /// error via `Display`.
48    pub message: Box<str>,
49}
50
51impl DatabaseErrorInfo {
52    pub fn new(message: impl Into<String>) -> Self {
53        Self {
54            message: message.into().into_boxed_str(),
55        }
56    }
57}