wayver's git archive


a simple self-hosted git server
git clone https://git.wayver.dev/bile

src/error.rs@71b17dd92232913d023854951d629e9876076719

raw
Date Commit Message Author Files + -
2026-02-19 17:51 large refactoring wayverd 53 2153 1683
...

1use std::{convert, fmt};
2
3use tracing_error::SpanTrace;
4
5pub type Result<T, E = Error> = std::result::Result<T, E>;
6
7#[must_use]
8pub struct Error {
9    span_trace: SpanTrace,
10
11    inner: anyhow::Error,
12}
13
14impl Error {
15    pub fn new(inner: anyhow::Error) -> Self {
16        let span_trace = SpanTrace::capture();
17
18        Self { span_trace, inner }
19    }
20
21    pub fn context<C>(self, context: C) -> Self
22    where
23        C: fmt::Display + Send + Sync + 'static,
24    {
25        let inner = self.inner.context(context);
26
27        Self { inner, ..self }
28    }
29}
30
31impl fmt::Display for Error {
32    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
33        fmt::Display::fmt(&self.inner, f)
34    }
35}
36
37impl fmt::Debug for Error {
38    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39        if f.alternate() {
40            return f
41                .debug_struct("Error")
42                .field("inner", &self.inner)
43                .field("span_trace", &self.span_trace)
44                .finish();
45        }
46
47        write!(f, "{:?}\n\nSpan traces:\n{}", self.inner, self.span_trace)
48    }
49}
50
51impl<E> From<E> for Error
52where
53    E: std::error::Error + Send + Sync + 'static,
54{
55    fn from(error: E) -> Self {
56        let span_trace = SpanTrace::capture();
57        let inner = anyhow::Error::from(error);
58        Self { span_trace, inner }
59    }
60}
61
62impl tracing_error::ExtractSpanTrace for Error {
63    fn span_trace(&self) -> Option<&SpanTrace> {
64        Some(&self.span_trace)
65    }
66}
67
68pub trait Context<T, E> {
69    fn context<C>(self, context: C) -> Result<T, Error>
70    where
71        C: fmt::Display + Send + Sync + 'static;
72
73    fn with_context<C, F>(self, f: F) -> Result<T, Error>
74    where
75        C: fmt::Display + Send + Sync + 'static,
76        F: FnOnce() -> C;
77}
78
79impl<T> Context<T, convert::Infallible> for Option<T> {
80    fn context<C>(self, context: C) -> Result<T, Error>
81    where
82        C: fmt::Display + Send + Sync + 'static,
83    {
84        self.map_or_else(
85            || Err(must_use(Error::new(::anyhow::format_err!("{context}")))),
86            |ok| Ok(ok),
87        )
88    }
89
90    fn with_context<C, F>(self, context: F) -> Result<T, Error>
91    where
92        C: fmt::Display + Send + Sync + 'static,
93        F: FnOnce() -> C,
94    {
95        self.map_or_else(
96            || Err(must_use(Error::new(::anyhow::format_err!("{}", context())))),
97            |ok| Ok(ok),
98        )
99    }
100}
101
102impl<T, E> Context<T, E> for Result<T, E>
103where
104    E: std::error::Error + Send + Sync + 'static,
105{
106    fn context<C>(self, context: C) -> Result<T, Error>
107    where
108        C: fmt::Display + Send + Sync + 'static,
109    {
110        match self {
111            Ok(ok) => Ok(ok),
112            Err(error) => Err(Error::new(anyhow::Error::new(error).context(context))),
113        }
114    }
115
116    fn with_context<C, F>(self, context: F) -> Result<T, Error>
117    where
118        C: fmt::Display + Send + Sync + 'static,
119        F: FnOnce() -> C,
120    {
121        match self {
122            Ok(ok) => Ok(ok),
123            Err(error) => Err(Error::new(anyhow::Error::new(error).context(context()))),
124        }
125    }
126}
127
128impl<T> Context<T, Error> for Result<T, Error> {
129    fn context<C>(self, context: C) -> Self
130    where
131        C: fmt::Display + Send + Sync + 'static,
132    {
133        match self {
134            Ok(ok) => Ok(ok),
135            Err(error) => Err(error.context(context)),
136        }
137    }
138
139    fn with_context<C, F>(self, context: F) -> Self
140    where
141        C: fmt::Display + Send + Sync + 'static,
142        F: FnOnce() -> C,
143    {
144        match self {
145            Ok(ok) => Ok(ok),
146            Err(error) => Err(error.context(context())),
147        }
148    }
149}
150
151#[doc(hidden)]
152#[inline]
153#[cold]
154pub const fn must_use(error: Error) -> Error {
155    error
156}
157