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, Failure, repr::ErrorRepr};
4
5/// An error container.
6///
7/// `Error<E>` is a lightweight handle to an error that can be cheaply cloned.
8/// It is `Send` and `Sync` when `E` is. It preserves the original error along
9/// with associated context such as the location where it occurred, the responsible
10/// service, a tag, a backtrace, and extension data.
11pub struct Error<E> {
12    pub(crate) inner: Arc<ErrorRepr<E>>,
13}
14
15impl<E> Error<E> {
16    /// Creates an error container associated with a service.
17    ///
18    /// Captures the caller location and associates the error with a service.
19    #[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    /// Creates an error container without service attribution.
35    ///
36    /// Captures the caller location.
37    #[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    /// Transforms this error into another error type.
53    ///
54    /// The closure receives the whole `Error<E>` container.
55    /// Preserves tag, service, backtrace, and extension data.
56    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    /// Returns a debug view of the error.
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 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    /// Sets the service responsible for this error.
102    ///
103    /// Returns the updated error.
104    #[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    /// Maps the inner error into a new error type using the provided closure.
114    ///
115    /// Preserves tag, 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    /// Converts the inner error into a new error type via `U: From<E>`.
128    ///
129    /// Preserves tag, 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    /// Tries to map the inner error into a value or another error type.
142    ///
143    /// On error, preserves tag, 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    /// Consumes this error and returns the inner error value.
156    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    /// Attaches a typed value to this `Error`.
161    ///
162    /// This value can be retrieved later using [`get_item`](Self::get_item).
163    #[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}