wayver's git archive


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

src/utils/error.rs@f3f2b40f0ffae5de2e6d3f661e32b582274bae49

raw
Date Commit Message Author Files + -
2026-02-17 21:59 small fixes wayverd 2 8 1
...

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