anyerror/
any_error_impl.rs1use std::error::Error;
2use std::fmt::Display;
3use std::fmt::Formatter;
4
5use serde::Deserialize;
6use serde::Serialize;
7
8#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Default)]
24#[cfg_attr(
25 feature = "rkyv",
26 derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize),
27 archive(
28 check_bytes,
29 bound(serialize = "__S: rkyv::ser::ScratchSpace + rkyv::ser::Serializer")
30 ),
31 archive_attr(check_bytes(
32 bound = "__C: rkyv::validation::ArchiveContext, <__C as rkyv::Fallible>::Error: std::error::Error"
33 ),)
34)]
35pub struct AnyError {
36 typ: Option<String>,
37
38 msg: String,
39
40 #[cfg_attr(feature = "rkyv", omit_bounds, archive_attr(omit_bounds))]
41 source: Option<Box<AnyError>>,
42
43 context: Vec<String>,
45
46 backtrace: Option<String>,
47}
48
49impl Display for AnyError {
50 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
51 if let Some(t) = &self.typ {
52 write!(f, "{}: ", t)?;
53 }
54
55 write!(f, "{}", self.msg)?;
56
57 for (i, ctx) in self.context.iter().enumerate() {
58 if f.alternate() {
59 writeln!(f)?;
60 write!(f, " while: {}", ctx)?;
61 } else {
62 if i > 0 {
63 write!(f, ",")?;
64 }
65 write!(f, " while: {}", ctx)?;
66 }
67 }
68
69 #[allow(clippy::collapsible_else_if)]
70 if f.alternate() {
71 if let Some(ref s) = self.source {
72 writeln!(f)?;
73 write!(f, "source: ")?;
74 write!(f, "{:#}", s)?;
75 }
76 } else {
77 if let Some(ref s) = self.source {
78 write!(f, "; source: {}", s)?;
79 }
80 }
81
82 Ok(())
83 }
84}
85
86impl std::fmt::Debug for AnyError {
87 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
88 <Self as Display>::fmt(self, f)?;
89
90 if let Some(ref b) = self.backtrace {
91 write!(f, "\nbacktrace:\n{}", b)?;
92 }
93 Ok(())
94 }
95}
96
97impl std::error::Error for AnyError {
98 fn source(&self) -> Option<&(dyn Error + 'static)> {
99 match &self.source {
100 Some(x) => Some(x.as_ref()),
101 None => None,
102 }
103 }
104}
105
106#[cfg(feature = "anyhow")]
107impl From<anyhow::Error> for AnyError {
108 fn from(a: anyhow::Error) -> Self {
109 let source = a.source().map(|x| Box::new(AnyError::from_dyn(x, None)));
114 #[cfg(feature = "backtrace")]
115 let bt = Some({
116 let bt = a.backtrace();
117 format!("{:?}", bt)
118 });
119
120 #[cfg(not(feature = "backtrace"))]
121 let bt = None;
122
123 Self {
124 typ: None,
125 msg: a.to_string(),
126 source,
127 context: vec![],
128 backtrace: bt,
129 }
130 }
131}
132
133impl<E> From<&E> for AnyError
134where E: std::error::Error + 'static
135{
136 fn from(e: &E) -> Self {
137 AnyError::new(e)
138 }
139}
140
141impl AnyError {
142 pub fn error(msg: impl ToString) -> Self {
144 Self {
145 typ: None,
146 msg: msg.to_string(),
147 source: None,
148 context: vec![],
149 backtrace: None,
150 }
151 }
152
153 pub fn new<E>(e: &E) -> Self
158 where E: Error + 'static {
159 let q: &(dyn Error + 'static) = e;
160
161 let x = q.downcast_ref::<AnyError>();
162 let typ = match x {
163 Some(ae) => ae.typ.clone(),
164 None => Some(std::any::type_name::<E>().to_string()),
165 };
166
167 Self::from_dyn(e, typ)
168 }
169
170 pub fn from_dyn(e: &(dyn Error + 'static), typ: Option<String>) -> Self {
171 let x = e.downcast_ref::<AnyError>();
172
173 match x {
174 Some(ae) => ae.clone(),
175 None => {
176 #[cfg(feature = "backtrace")]
177 let bt = crate::bt::error_backtrace_str(e);
178
179 #[cfg(not(feature = "backtrace"))]
180 let bt = None;
181
182 let source = e.source().map(|x| Box::new(AnyError::from_dyn(x, None)));
183
184 Self {
185 typ,
186 msg: e.to_string(),
187 source,
188 context: vec![],
189 backtrace: bt,
190 }
191 }
192 }
193 }
194
195 #[cfg(feature = "backtrace")]
196 #[must_use]
197 pub fn with_backtrace(mut self) -> Self {
198 if self.backtrace.is_some() {
199 return self;
200 }
201
202 self.backtrace = Some(crate::bt::new_str());
203 self
204 }
205
206 #[must_use]
207 pub fn add_context<D: Display, F: FnOnce() -> D>(mut self, ctx: F) -> Self {
208 self.context.push(format!("{}", ctx()));
209 self
210 }
211
212 pub fn with_type<T: ToString>(mut self, typ: Option<T>) -> Self {
214 self.typ = typ.map(|x| x.to_string());
215 self
216 }
217
218 pub fn get_type(&self) -> Option<&str> {
220 self.typ.as_ref().map(|x| x as _)
221 }
222
223 pub fn backtrace(&self) -> Option<&str> {
224 self.backtrace.as_ref().map(|x| x as _)
225 }
226}
227
228pub fn backtrace_str() -> Option<String> {
231 #[cfg(feature = "backtrace")]
232 return Some(crate::bt::new_str());
233
234 #[cfg(not(feature = "backtrace"))]
235 return None;
236}