Skip to main content

ntex_error/
error.rs

1use std::{error, fmt, ops, panic::Location, sync::Arc};
2
3use crate::{AsError, Backtrace, Bytes, ErrorDiagnostic, ErrorMapping, repr::ErrorRepr};
4
5/// An error container.
6///
7/// `Error<E>` is a lightweight handle to an error that can be cheaply cloned
8/// and safely shared across threads. It preserves the original error along with
9/// associated context such as where it occurred.
10pub struct Error<E> {
11    pub(crate) inner: Arc<ErrorRepr<E>>,
12}
13
14impl<E> Error<E> {
15    /// Creates a new error container.
16    ///
17    /// Captures the caller location and associates the error with a service.
18    #[track_caller]
19    pub fn new<T>(error: T, service: &'static str) -> Self
20    where
21        E: From<T>,
22    {
23        Self {
24            inner: Arc::new(ErrorRepr::new3(
25                E::from(error),
26                None,
27                Some(service),
28                Location::caller(),
29            )),
30        }
31    }
32
33    /// Creates a new error container.
34    ///
35    /// Captures the caller location and associates the error with a service.
36    #[track_caller]
37    pub fn from_err<T>(error: T) -> Self
38    where
39        E: From<T>,
40    {
41        Self {
42            inner: Arc::new(ErrorRepr::new3(
43                error.into(),
44                None,
45                None,
46                Location::caller(),
47            )),
48        }
49    }
50
51    /// Transforms the inner error into another error type.
52    ///
53    /// Preserves `service`, backtrace, and extension data.
54    pub fn forward<U, F>(self, f: F) -> Error<U>
55    where
56        F: FnOnce(Error<E>) -> U,
57    {
58        let svc = self.inner.service;
59        let tag = self.inner.tag.clone();
60        let bt = self.inner.backtrace.clone();
61        let ext = self.inner.ext.clone();
62
63        Error {
64            inner: Arc::new(ErrorRepr::new2(f(self), tag, svc, bt, ext)),
65        }
66    }
67
68    /// Returns a debug view of the error.
69    ///
70    /// Intended for debugging purposes.
71    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    /// Returns a reference to a previously stored value of type `T` from this error.
81    ///
82    /// This can be used to access additional contextual data attached to the error.
83    pub fn get_item<T: 'static>(&self) -> Option<&T> {
84        self.inner.ext.get::<T>()
85    }
86}
87
88impl<E: Clone> Error<E> {
89    /// Sets a user-defined tag on this error.
90    ///
91    /// Returns the updated error.
92    #[must_use]
93    pub fn set_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    /// Sets the service responsible for this error.
102    ///
103    /// Returns the updated error.
104    #[must_use]
105    pub fn set_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    /// Maps the inner error into a new error type.
114    ///
115    /// Preserves `service`, backtrace, and extension data.
116    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    /// Maps the inner error into a new error type.
128    ///
129    /// Preserves `service`, backtrace, and extension data.
130    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    /// Try to map inner error to new error.
142    ///
143    /// Preserves `service`, backtrace, and extension data.
144    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    /// Attaches a typed value to this `Error`.
156    ///
157    /// This value can be retrieved later using `get_item::<T>()`.
158    #[must_use]
159    pub fn insert_item<T: Sync + Send + 'static>(self, val: T) -> Self {
160        Error {
161            inner: ErrorRepr::with_mut(self.inner, move |inner| {
162                inner.ext.insert(val);
163            }),
164        }
165    }
166}
167
168impl<E: Clone> Error<E> {
169    /// Consumes this error and returns the inner error value.
170    pub fn into_error(self) -> E {
171        Arc::try_unwrap(self.inner).map_or_else(|inner| inner.error.clone(), |inner| inner.error)
172    }
173}
174
175impl<E> Clone for Error<E> {
176    fn clone(&self) -> Error<E> {
177        Error {
178            inner: self.inner.clone(),
179        }
180    }
181}
182
183impl<E: error::Error> From<E> for Error<E> {
184    #[track_caller]
185    fn from(error: E) -> Self {
186        Self {
187            inner: Arc::new(ErrorRepr::new3(error, None, None, Location::caller())),
188        }
189    }
190}
191
192impl<E> Eq for Error<E> where E: Eq {}
193
194impl<E> PartialEq for Error<E>
195where
196    E: PartialEq,
197{
198    fn eq(&self, other: &Self) -> bool {
199        self.inner.error.eq(&other.inner.error) && self.inner.service == other.inner.service
200    }
201}
202
203impl<E> PartialEq<E> for Error<E>
204where
205    E: PartialEq,
206{
207    fn eq(&self, other: &E) -> bool {
208        self.inner.error.eq(other)
209    }
210}
211
212impl<E> ops::Deref for Error<E> {
213    type Target = E;
214
215    fn deref(&self) -> &E {
216        &self.inner.error
217    }
218}
219
220impl<E: error::Error + 'static> error::Error for Error<E> {
221    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
222        self.inner.error.source()
223    }
224}
225
226impl<E: ErrorDiagnostic> AsError for Error<E> {
227    type Target = E;
228
229    fn as_diag(&self) -> &E {
230        self
231    }
232}
233
234impl<E: ErrorDiagnostic> ErrorDiagnostic for Error<E> {
235    fn signature(&self) -> &'static str {
236        self.inner.signature()
237    }
238
239    fn tag(&self) -> Option<&Bytes> {
240        self.inner.tag()
241    }
242
243    fn service(&self) -> Option<&'static str> {
244        self.inner.service()
245    }
246
247    fn backtrace(&self) -> Option<&Backtrace> {
248        self.inner.backtrace()
249    }
250}
251
252impl<T, E, U> ErrorMapping<T, E, U> for Result<T, E>
253where
254    U: From<E>,
255{
256    fn into_error(self) -> Result<T, Error<U>> {
257        match self {
258            Ok(val) => Ok(val),
259            Err(err) => Err(Error {
260                inner: Arc::new(ErrorRepr::new3(
261                    U::from(err),
262                    None,
263                    None,
264                    Location::caller(),
265                )),
266            }),
267        }
268    }
269}
270
271impl<T, E, U> ErrorMapping<T, E, U> for Result<T, Error<E>>
272where
273    U: From<E>,
274    E: Clone,
275{
276    fn into_error(self) -> Result<T, Error<U>> {
277        match self {
278            Ok(val) => Ok(val),
279            Err(err) => Err(err.map(U::from)),
280        }
281    }
282}
283
284impl<E: fmt::Display> fmt::Display for Error<E> {
285    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
286        fmt::Display::fmt(&self.inner.error, f)
287    }
288}
289
290impl<E: fmt::Debug> fmt::Debug for Error<E> {
291    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
292        fmt::Debug::fmt(&self.inner.error, f)
293    }
294}
295
296struct ErrorDebug<'a, E> {
297    inner: &'a ErrorRepr<E>,
298}
299
300impl<E: fmt::Debug> fmt::Debug for ErrorDebug<'_, E> {
301    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
302        f.debug_struct("Error")
303            .field("error", &self.inner.error)
304            .field("service", &self.inner.service)
305            .field("tag", &self.inner.tag)
306            .field("backtrace", &self.inner.backtrace)
307            .finish()
308    }
309}