From d5467dca8e10c5940820f218b8b418fd3146783d Mon Sep 17 00:00:00 2001 From: Anatol Belski Date: Wed, 4 Mar 2026 22:29:54 +0100 Subject: [PATCH] block: Add BlockError struct with Display and Error impls Add the single public crate error type. It combines a BlockErrorKind for classification, an optional boxed source for the underlying cause, and an optional ErrorContext for diagnostics. Display renders the kind and context only, leaving source traversal to error reporters so the cause chain is not duplicated in human readable output. Signed-off-by: Anatol Belski --- block/src/error.rs | 46 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/block/src/error.rs b/block/src/error.rs index b94ddda06..13d971685 100644 --- a/block/src/error.rs +++ b/block/src/error.rs @@ -16,6 +16,7 @@ //! +-- io::Error / etc. //! ``` +use std::error::Error as StdError; use std::fmt::{self, Display, Formatter}; use std::path::PathBuf; @@ -46,12 +47,12 @@ impl Display for BlockErrorKind { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match self { Self::Io => write!(f, "I/O error"), - Self::InvalidFormat => write!(f, "invalid format"), - Self::UnsupportedFeature => write!(f, "unsupported feature"), - Self::CorruptImage => write!(f, "corrupt image"), - Self::OutOfBounds => write!(f, "out of bounds"), - Self::NotFound => write!(f, "not found"), - Self::Overflow => write!(f, "overflow"), + Self::InvalidFormat => write!(f, "Invalid format"), + Self::UnsupportedFeature => write!(f, "Unsupported feature"), + Self::CorruptImage => write!(f, "Corrupt image"), + Self::OutOfBounds => write!(f, "Out of bounds"), + Self::NotFound => write!(f, "Not found"), + Self::Overflow => write!(f, "Overflow"), } } } @@ -109,3 +110,36 @@ impl Display for ErrorContext { Ok(()) } } + +/// Unified error type for the block crate. +/// +/// Pairs a stable [`BlockErrorKind`] classification with an optional +/// boxed source error (format-specific) and optional [`ErrorContext`]. +/// +/// Display renders kind + context only; the underlying cause is +/// exposed via [`std::error::Error::source()`] for reporters that +/// walk the chain. +#[derive(Debug)] +pub struct BlockError { + kind: BlockErrorKind, + source: Option>, + ctx: Option, +} + +impl Display for BlockError { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.kind)?; + if let Some(ctx) = &self.ctx { + write!(f, " ({ctx})")?; + } + Ok(()) + } +} + +impl StdError for BlockError { + fn source(&self) -> Option<&(dyn StdError + 'static)> { + self.source + .as_ref() + .map(|e| e.as_ref() as &(dyn StdError + 'static)) + } +}