Skip to main content

ntex_error/
info.rs

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