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}