Skip to main content

ntex_error/
info.rs

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