1use std::{error, fmt, ops, panic::Location, sync::Arc};
2
3use crate::{AsError, Backtrace, Bytes, ErrorDiagnostic, ErrorMapping, Failure, repr::ErrorRepr};
4
5pub struct Error<E> {
12 pub(crate) inner: Arc<ErrorRepr<E>>,
13}
14
15impl<E> Error<E> {
16 #[track_caller]
20 pub fn new<T>(error: T, service: &'static str) -> Self
21 where
22 E: From<T>,
23 {
24 Self {
25 inner: Arc::new(ErrorRepr::new3(
26 E::from(error),
27 None,
28 Some(service),
29 Location::caller(),
30 )),
31 }
32 }
33
34 #[track_caller]
38 pub fn from_err<T>(error: T) -> Self
39 where
40 E: From<T>,
41 {
42 Self {
43 inner: Arc::new(ErrorRepr::new3(
44 error.into(),
45 None,
46 None,
47 Location::caller(),
48 )),
49 }
50 }
51
52 pub fn forward<U, F>(self, f: F) -> Error<U>
57 where
58 F: FnOnce(Error<E>) -> U,
59 {
60 let svc = self.inner.service;
61 let tag = self.inner.tag.clone();
62 let bt = self.inner.backtrace.clone();
63 let ext = self.inner.ext.clone();
64
65 Error {
66 inner: Arc::new(ErrorRepr::new2(f(self), tag, svc, bt, ext)),
67 }
68 }
69
70 pub fn debug(&self) -> impl fmt::Debug
72 where
73 E: fmt::Debug,
74 {
75 ErrorDebug {
76 inner: self.inner.as_ref(),
77 }
78 }
79
80 pub fn get_item<T: 'static>(&self) -> Option<&T> {
84 self.inner.ext.get::<T>()
85 }
86}
87
88impl<E: Clone> Error<E> {
89 #[must_use]
93 pub fn with_tag<T: Into<Bytes>>(self, tag: T) -> Self {
94 Error {
95 inner: ErrorRepr::with_mut(self.inner, move |inner| {
96 inner.tag = Some(tag.into());
97 }),
98 }
99 }
100
101 #[must_use]
105 pub fn with_service(self, name: &'static str) -> Self {
106 Error {
107 inner: ErrorRepr::with_mut(self.inner, move |inner| {
108 inner.service = Some(name);
109 }),
110 }
111 }
112
113 pub fn map<U, F>(self, f: F) -> Error<U>
117 where
118 F: FnOnce(E) -> U,
119 {
120 let (err, tag, svc, bt, ext) = ErrorRepr::unpack(self.inner);
121
122 Error {
123 inner: Arc::new(ErrorRepr::new2(f(err), tag, svc, bt, ext)),
124 }
125 }
126
127 pub fn map_err<U>(self) -> Error<U>
131 where
132 U: From<E>,
133 {
134 let (err, tag, svc, bt, ext) = ErrorRepr::unpack(self.inner);
135
136 Error {
137 inner: Arc::new(ErrorRepr::new2(err.into(), tag, svc, bt, ext)),
138 }
139 }
140
141 pub fn try_map<T, U, F>(self, f: F) -> Result<T, Error<U>>
145 where
146 F: FnOnce(E) -> Result<T, U>,
147 {
148 let (err, tag, svc, bt, ext) = ErrorRepr::unpack(self.inner);
149
150 f(err).map_err(move |err| Error {
151 inner: Arc::new(ErrorRepr::new2(err, tag, svc, bt, ext)),
152 })
153 }
154
155 pub fn into_error(self) -> E {
157 Arc::try_unwrap(self.inner).map_or_else(|inner| inner.error.clone(), |inner| inner.error)
158 }
159
160 #[must_use]
164 pub fn with_item<T: Sync + Send + 'static>(self, val: T) -> Self {
165 Error {
166 inner: ErrorRepr::with_mut(self.inner, move |inner| {
167 inner.ext.insert(val);
168 }),
169 }
170 }
171}
172
173impl<E> Clone for Error<E> {
174 fn clone(&self) -> Error<E> {
175 Error {
176 inner: self.inner.clone(),
177 }
178 }
179}
180
181impl<E> From<E> for Error<E> {
182 #[track_caller]
183 fn from(error: E) -> Self {
184 Self {
185 inner: Arc::new(ErrorRepr::new3(error, None, None, Location::caller())),
186 }
187 }
188}
189
190impl<E> Eq for Error<E> where E: Eq {}
191
192impl<E> PartialEq for Error<E>
193where
194 E: PartialEq,
195{
196 fn eq(&self, other: &Self) -> bool {
197 self.inner.error.eq(&other.inner.error) && self.inner.service == other.inner.service
198 }
199}
200
201impl<E> PartialEq<E> for Error<E>
202where
203 E: PartialEq,
204{
205 fn eq(&self, other: &E) -> bool {
206 self.inner.error.eq(other)
207 }
208}
209
210impl<E> ops::Deref for Error<E> {
211 type Target = E;
212
213 fn deref(&self) -> &E {
214 &self.inner.error
215 }
216}
217
218impl<E: error::Error + 'static> error::Error for Error<E> {
219 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
220 self.inner.error.source()
221 }
222}
223
224impl<E: ErrorDiagnostic> AsError for Error<E> {
225 type Target = E;
226
227 fn as_diag(&self) -> &E {
228 self
229 }
230}
231
232impl<E: ErrorDiagnostic> ErrorDiagnostic for Error<E> {
233 fn signature(&self) -> &'static str {
234 self.inner.signature()
235 }
236
237 fn tag(&self) -> Option<&Bytes> {
238 self.inner.tag()
239 }
240
241 fn service(&self) -> Option<&'static str> {
242 self.inner.service()
243 }
244
245 fn backtrace(&self) -> Option<&Backtrace> {
246 self.inner.backtrace()
247 }
248
249 fn into_failure(self) -> Failure {
250 Failure::from(self)
251 }
252}
253
254impl<T, E, U> ErrorMapping<T, E, U> for Result<T, E>
255where
256 U: From<E>,
257{
258 #[track_caller]
259 fn into_error(self) -> Result<T, Error<U>> {
260 match self {
261 Ok(val) => Ok(val),
262 Err(err) => Err(Error {
263 inner: Arc::new(ErrorRepr::new3(
264 U::from(err),
265 None,
266 None,
267 Location::caller(),
268 )),
269 }),
270 }
271 }
272}
273
274impl<T, E, U> ErrorMapping<T, E, U> for Result<T, Error<E>>
275where
276 U: From<E>,
277 E: Clone,
278{
279 fn into_error(self) -> Result<T, Error<U>> {
280 match self {
281 Ok(val) => Ok(val),
282 Err(err) => Err(err.map(U::from)),
283 }
284 }
285}
286
287impl<E: fmt::Display> fmt::Display for Error<E> {
288 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
289 fmt::Display::fmt(&self.inner.error, f)
290 }
291}
292
293impl<E: fmt::Debug> fmt::Debug for Error<E> {
294 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
295 fmt::Debug::fmt(&self.inner.error, f)
296 }
297}
298
299struct ErrorDebug<'a, E> {
300 inner: &'a ErrorRepr<E>,
301}
302
303impl<E: fmt::Debug> fmt::Debug for ErrorDebug<'_, E> {
304 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
305 f.debug_struct("Error")
306 .field("error", &self.inner.error)
307 .field("tag", &self.inner.tag)
308 .field("service", &self.inner.service)
309 .field("backtrace", &self.inner.backtrace)
310 .finish()
311 }
312}