1mod root_err;
2mod std_err;
3
4use std::{
5 any::TypeId,
6 error::Error,
7 fmt::{self, Debug, Display, Formatter},
8};
9
10use self::{root_err::RootErr, std_err::StdErr};
11use crate::{Backtrace, Error2, Location, SourceToTarget, private};
12
13pub enum ErrorKind<E, B> {
14 Std { source: E, backtrace: B },
15 Err2 { source: E },
16}
17
18pub struct BoxedError2 {
19 source: Box<dyn Error2 + Send + Sync + 'static>,
20}
21
22impl BoxedError2 {
23 #[inline]
24 const fn source_ref(&self) -> &(dyn Error + Send + Sync + 'static) {
25 &*self.source
26 }
27
28 #[inline]
29 const fn source_mut(&mut self) -> &mut (dyn Error + Send + Sync + 'static) {
30 &mut *self.source
31 }
32
33 #[inline]
34 fn source(self) -> Box<dyn Error + Send + Sync + 'static> {
35 self.source
36 }
37
38 #[inline]
39 pub fn is_root(&self) -> bool {
40 self.source_ref().is::<RootErr>()
41 }
42
43 fn generic_is_root<T: Error + 'static>() -> bool {
44 TypeId::of::<RootErr>() == TypeId::of::<T>()
45 }
46
47 #[inline]
48 pub fn is<T: Error + 'static>(&self) -> bool {
49 debug_assert!(!Self::generic_is_root::<T>());
50 let source = self.source_ref();
51
52 source.is::<StdErr<T>>() || source.is::<T>()
53 }
54
55 #[inline]
56 pub fn downcast_ref<T: Error + 'static>(&self) -> Option<ErrorKind<&T, &Backtrace>> {
57 debug_assert!(!Self::generic_is_root::<T>());
58 let source = self.source_ref();
59
60 if let Some(StdErr { source, backtrace }) = source.downcast_ref::<StdErr<T>>() {
61 Some(ErrorKind::Std { source, backtrace })
62 } else if let Some(source) = source.downcast_ref::<T>() {
63 Some(ErrorKind::Err2 { source })
64 } else {
65 None
66 }
67 }
68
69 #[inline]
70 pub fn downcast_mut<T: Error + 'static>(
71 &mut self,
72 ) -> Option<ErrorKind<&mut T, &mut Backtrace>> {
73 debug_assert!(!Self::generic_is_root::<T>());
74 let source = self.source_ref();
75
76 if source.is::<StdErr<T>>() {
77 let StdErr { source, backtrace } =
78 self.source_mut().downcast_mut::<StdErr<T>>().unwrap();
79 Some(ErrorKind::Std { source, backtrace })
80 } else if source.is::<T>() {
81 let source = self.source_mut().downcast_mut::<T>().unwrap();
82 Some(ErrorKind::Err2 { source })
83 } else {
84 None
85 }
86 }
87
88 #[inline]
89 pub fn downcast<T: Error + 'static>(self) -> Result<ErrorKind<T, Backtrace>, Self> {
90 debug_assert!(!Self::generic_is_root::<T>());
91 let source = self.source_ref();
92
93 if source.is::<StdErr<T>>() {
94 let StdErr { source, backtrace } = *self.source().downcast::<StdErr<T>>().unwrap();
95 Ok(ErrorKind::Std { source, backtrace })
96 } else if source.is::<T>() {
97 let source = *self.source().downcast::<T>().unwrap();
98 Ok(ErrorKind::Err2 { source })
99 } else {
100 Err(self)
101 }
102 }
103}
104
105impl Display for BoxedError2 {
106 #[inline]
107 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
108 Display::fmt(&self.source, f)
109 }
110}
111
112impl Debug for BoxedError2 {
113 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
114 if f.alternate() {
115 Debug::fmt(&self.source, f)
116 } else {
117 Display::fmt(&self.source, f)?;
118 write!(f, "\n\n")?;
119
120 let m = self.backtrace().error_message();
121 Display::fmt(&m, f)
122 }
123 }
124}
125
126impl Error for BoxedError2 {
127 #[inline]
128 fn source(&self) -> Option<&(dyn Error + 'static)> {
129 if self.is_root() {
130 None
131 } else {
132 Some(&*self.source)
133 }
134 }
135}
136
137impl Error2 for BoxedError2 {
138 #[inline]
139 fn backtrace(&self) -> &Backtrace {
140 self.source.backtrace()
141 }
142
143 #[inline]
144 fn backtrace_mut(&mut self) -> &mut Backtrace {
145 self.source.backtrace_mut()
146 }
147}
148
149impl BoxedError2 {
150 #[track_caller]
151 #[inline]
152 pub fn from_root<R>(root: R) -> BoxedError2
153 where
154 R: Display + Debug + Send + Sync + 'static,
155 {
156 Self::from_root_with_location(root, Location::caller())
157 }
158
159 pub fn from_root_with_location<R>(root: R, location: Location) -> BoxedError2
160 where
161 R: Display + Debug + Send + Sync + 'static,
162 {
163 let mut error = BoxedError2 {
164 source: Box::new(RootErr::new(root)),
165 };
166
167 crate::push_error(&mut error, location);
168
169 error
170 }
171
172 #[track_caller]
173 #[inline]
174 pub fn from_std<T>(source: T) -> BoxedError2
175 where
176 T: Error + Send + Sync + 'static,
177 {
178 Self::from_std_with_location(source, Location::caller())
179 }
180
181 pub fn from_std_with_location<T>(source: T, location: Location) -> BoxedError2
182 where
183 T: Error + Send + Sync + 'static,
184 {
185 if (&source as &(dyn Error + Send + Sync)).is::<BoxedError2>() {
186 let mut e =
187 <dyn Error + Send + Sync>::downcast::<BoxedError2>(Box::new(source)).unwrap();
188
189 e.backtrace_mut().push_location(location);
190 *e
191 } else {
192 let mut error = BoxedError2 {
193 source: Box::new(StdErr::new(source)),
194 };
195
196 crate::push_error(&mut error, location);
197
198 error
199 }
200 }
201
202 #[track_caller]
203 #[inline]
204 pub fn from_err2<T>(source: T) -> BoxedError2
205 where
206 T: Error2 + Send + Sync + 'static,
207 {
208 Self::from_err2_with_location(source, Location::caller())
209 }
210
211 pub fn from_err2_with_location<T>(source: T, location: Location) -> BoxedError2
212 where
213 T: Error2 + Send + Sync + 'static,
214 {
215 if (&source as &(dyn Error + Send + Sync)).is::<BoxedError2>() {
216 let mut e =
217 <dyn Error + Send + Sync>::downcast::<BoxedError2>(Box::new(source)).unwrap();
218
219 e.backtrace_mut().push_location(location);
220 *e
221 } else {
222 let mut error = BoxedError2 {
223 source: Box::new(source),
224 };
225
226 crate::push_error(&mut error, location);
227
228 error
229 }
230 }
231}
232
233pub struct ViaRoot<M>(pub M)
234where
235 M: Display + Debug + Send + Sync + 'static;
236
237impl<M> SourceToTarget<private::ViaFull, (), (), BoxedError2> for ViaRoot<M>
238where
239 M: Display + Debug + Send + Sync + 'static,
240{
241 #[inline]
242 fn source_to_target(self, _source: (), location: Location) -> BoxedError2 {
243 BoxedError2::from_root_with_location(self.0, location)
244 }
245}
246
247pub struct ViaStd;
248
249impl<T> SourceToTarget<private::ViaFull, T, T, BoxedError2> for ViaStd
250where
251 T: Error + Send + Sync + 'static,
252{
253 #[inline]
254 fn source_to_target(self, source: T, location: Location) -> BoxedError2 {
255 BoxedError2::from_std_with_location(source, location)
256 }
257}
258
259pub struct ViaErr2;
260
261impl<T> SourceToTarget<private::ViaFull, T, T, BoxedError2> for ViaErr2
262where
263 T: Error2 + Send + Sync + 'static,
264{
265 #[inline]
266 fn source_to_target(self, source: T, location: Location) -> BoxedError2 {
267 BoxedError2::from_err2_with_location(source, location)
268 }
269}