raw
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