raw
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