wayver's git archive


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

src/utils/error.rs@375565f690b958e08f589a7fee998ad5f47a70d0

raw
Date Commit Message Author Files + -
2026-02-17 21:07 initial mvp wayverd 74 10800 0
...

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