Skip to main content

ntex_error/
info.rs

1use ntex_bytes::Bytes;
2use std::{any::Any, any::TypeId, error, fmt, sync::Arc};
3
4use crate::{AsError, Backtrace, Error, ErrorDiagnostic, IntoFailure, repr::ErrorRepr};
5
6trait ErrorInfo: fmt::Display + fmt::Debug + 'static {
7    fn tag(&self) -> Option<&crate::Bytes>;
8
9    fn service(&self) -> Option<&'static str>;
10
11    fn signature(&self) -> &'static str;
12
13    fn backtrace(&self) -> Option<&Backtrace>;
14
15    fn source(&self) -> Option<&(dyn error::Error + 'static)>;
16
17    fn get_item(&self, id: &TypeId) -> Option<&(dyn Any + Send + Sync)>;
18}
19
20impl<E> ErrorInfo for ErrorRepr<E>
21where
22    E: ErrorDiagnostic,
23{
24    fn tag(&self) -> Option<&crate::Bytes> {
25        ErrorDiagnostic::tag(self)
26    }
27
28    fn service(&self) -> Option<&'static str> {
29        ErrorDiagnostic::service(self)
30    }
31
32    fn signature(&self) -> &'static str {
33        self.error.signature()
34    }
35
36    fn backtrace(&self) -> Option<&Backtrace> {
37        ErrorDiagnostic::backtrace(self)
38    }
39
40    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
41        self.error.source()
42    }
43
44    fn get_item(&self, id: &TypeId) -> Option<&(dyn Any + Send + Sync)> {
45        self.ext.map.get(id).map(AsRef::as_ref)
46    }
47}
48
49/// Type-erased container holding error information.
50///
51/// This allows storing and passing error metadata without exposing the concrete type.
52pub struct Failure {
53    inner: FailureDiagnostic,
54}
55
56pub struct FailureDiagnostic(Arc<dyn ErrorInfo>);
57
58impl Failure {
59    /// Returns an optional tag associated with this error.
60    pub fn tag(&self) -> Option<&crate::Bytes> {
61        self.inner.0.tag()
62    }
63
64    /// Returns the name of the responsible service, if applicable.
65    pub fn service(&self) -> Option<&'static str> {
66        self.inner.0.service()
67    }
68
69    /// Returns a stable identifier for the specific error classification.
70    pub fn signature(&self) -> &'static str {
71        self.inner.0.signature()
72    }
73
74    /// Returns a backtrace for debugging purposes, if available.
75    pub fn backtrace(&self) -> Option<&Backtrace> {
76        self.inner.0.backtrace()
77    }
78
79    /// Returns a reference to a previously stored value of type `T` from this error.
80    pub fn get_item<T: 'static>(&self) -> Option<&T> {
81        self.inner
82            .0
83            .get_item(&TypeId::of::<T>())
84            .and_then(|boxed| boxed.downcast_ref())
85    }
86}
87
88impl<E> From<Error<E>> for Failure
89where
90    E: ErrorDiagnostic,
91{
92    fn from(err: Error<E>) -> Self {
93        Self {
94            inner: FailureDiagnostic(err.inner),
95        }
96    }
97}
98
99impl<E> From<&Error<E>> for Failure
100where
101    E: ErrorDiagnostic,
102{
103    fn from(err: &Error<E>) -> Self {
104        Self {
105            inner: FailureDiagnostic(err.inner.clone()),
106        }
107    }
108}
109
110impl IntoFailure for Failure {
111    fn fail(self) -> Failure {
112        self
113    }
114}
115
116impl<E> IntoFailure for E
117where
118    E: ErrorDiagnostic + Into<Error<E>>,
119{
120    fn fail(self) -> Failure {
121        Failure {
122            inner: FailureDiagnostic(self.into().inner),
123        }
124    }
125}
126
127impl error::Error for Failure {
128    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
129        self.inner.source()
130    }
131}
132
133impl fmt::Debug for Failure {
134    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
135        fmt::Debug::fmt(&self.inner, f)
136    }
137}
138
139impl fmt::Display for Failure {
140    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
141        fmt::Display::fmt(&self.inner, f)
142    }
143}
144
145impl Clone for Failure {
146    fn clone(&self) -> Self {
147        Failure {
148            inner: FailureDiagnostic(self.inner.0.clone()),
149        }
150    }
151}
152
153impl AsError for Failure {
154    type Target = FailureDiagnostic;
155
156    fn as_diag(&self) -> &FailureDiagnostic {
157        &self.inner
158    }
159}
160
161impl ErrorDiagnostic for FailureDiagnostic {
162    fn signature(&self) -> &'static str {
163        self.0.signature()
164    }
165
166    fn tag(&self) -> Option<&Bytes> {
167        self.0.tag()
168    }
169
170    fn service(&self) -> Option<&'static str> {
171        self.0.service()
172    }
173
174    fn backtrace(&self) -> Option<&Backtrace> {
175        self.0.backtrace()
176    }
177}
178
179impl error::Error for FailureDiagnostic {
180    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
181        self.0.source()
182    }
183}
184
185impl fmt::Debug for FailureDiagnostic {
186    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
187        fmt::Debug::fmt(&self.0, f)
188    }
189}
190
191impl fmt::Display for FailureDiagnostic {
192    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
193        fmt::Display::fmt(&self.0, f)
194    }
195}