rust / expert
Snippet
Designing a Custom Error Hierarchy with Source Chaining
To build robust libraries in Rust, you should design custom errors that implement std::error::Error. By overriding the source method, you expose the underlying cause (the source error) of your wrapper error, enabling callers to traverse the full chain of failures using standard diagnostic tools.
snippet.rs
rust
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
use std::error::Error;use std::fmt;#[derive(Debug)]pub enum DatabaseError {QueryFailed(String),ConnectionLost,}impl fmt::Display for DatabaseError {fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {match self {Self::QueryFailed(q) => write!(f, "Database query failed: {}", q),Self::ConnectionLost => write!(f, "Database connection lost"),}}}impl Error for DatabaseError {}#[derive(Debug)]pub struct ApplicationError {context: String,source: DatabaseError,}impl fmt::Display for ApplicationError {fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {write!(f, "Application error occurred: {}", self.context)}}impl Error for ApplicationError {fn source(&self) -> Option<&(dyn Error + 'static)> {Some(&self.source)}}
Breakdown
1
impl Error for DatabaseError {}
Implements the Error trait with default behavior since it has no underlying cause.
2
source: DatabaseError,
Stores the lower-level error inside the high-level application error struct.
3
fn source(&self) -> Option<&(dyn Error + 'static)> {
Overrides source to return a reference to the nested error wrapped in a trait object.