1use std::collections::VecDeque;
16use std::error::Error;
17use std::fmt;
18use std::marker::PhantomData;
19use std::ops::Deref;
20use std::panic::Location;
21
22use crate::{write_location, ChainedError, Exn};
23
24impl<E: Error + Send + Sync + 'static> From<E> for Exn<E> {
25 #[track_caller]
26 fn from(error: E) -> Self {
27 Exn::new(error)
28 }
29}
30
31impl<E: Error + Send + Sync + 'static> Exn<E> {
32 #[track_caller]
43 pub fn new(error: E) -> Self {
44 fn walk_sources(error: &dyn Error, location: &'static Location<'static>) -> Vec<Frame> {
45 if let Some(source) = error.source() {
46 let children = vec![Frame {
47 error: Box::new(SourceError::new(source)),
48 location,
49 children: walk_sources(source, location),
50 }];
51 children
52 } else {
53 vec![]
54 }
55 }
56
57 let location = Location::caller();
58 let children = walk_sources(&error, location);
59 let frame = Frame {
60 error: Box::new(error),
61 location,
62 children,
63 };
64
65 Self {
66 frame: Box::new(frame),
67 phantom: PhantomData,
68 }
69 }
70
71 #[track_caller]
73 pub fn raise_all<T, I>(children: I, err: E) -> Self
74 where
75 T: Error + Send + Sync + 'static,
76 I: IntoIterator,
77 I::Item: Into<Exn<T>>,
78 {
79 let mut new_exn = Exn::new(err);
80 for exn in children {
81 let exn = exn.into();
82 new_exn.frame.children.push(*exn.frame);
83 }
84 new_exn
85 }
86
87 #[track_caller]
89 pub fn raise<T: Error + Send + Sync + 'static>(self, err: T) -> Exn<T> {
90 let mut new_exn = Exn::new(err);
91 new_exn.frame.children.push(*self.frame);
92 new_exn
93 }
94
95 #[track_caller]
97 pub fn chain<T: Error + Send + Sync + 'static>(mut self, err: impl Into<Exn<T>>) -> Exn<E> {
98 let err = err.into();
99 self.frame.children.push(*err.frame);
100 self
101 }
102
103 #[track_caller]
105 pub fn chain_all<T, I>(mut self, errors: I) -> Exn<E>
106 where
107 T: Error + Send + Sync + 'static,
108 I: IntoIterator,
109 I::Item: Into<Exn<T>>,
110 {
111 for err in errors {
112 let err = err.into();
113 self.frame.children.push(*err.frame);
114 }
115 self
116 }
117
118 pub fn drain_children(&mut self) -> impl Iterator<Item = Exn> + '_ {
122 self.frame.children.drain(..).map(Exn::from)
123 }
124
125 pub fn erased(self) -> Exn {
127 let untyped_frame = {
128 let Frame {
129 error,
130 location,
131 children,
132 } = *self.frame;
133 let error = Untyped(error);
136 Frame {
137 error: Box::new(error),
138 location,
139 children,
140 }
141 };
142 Exn {
143 frame: Box::new(untyped_frame),
144 phantom: Default::default(),
145 }
146 }
147
148 pub fn error(&self) -> &E {
150 self.frame
151 .error
152 .downcast_ref()
153 .expect("the owned frame always matches the compile-time error type")
154 }
155
156 pub fn into_box(self) -> Box<E> {
161 match self.frame.error.downcast() {
162 Ok(err) => err,
163 Err(_) => unreachable!("The type in the frame is always the type of this instance"),
164 }
165 }
166
167 pub fn into_inner(self) -> E {
172 *self.into_box()
173 }
174
175 pub fn into_error(self) -> crate::Error {
179 self.into()
180 }
181
182 pub fn into_chain(self) -> crate::ChainedError {
187 self.into()
188 }
189
190 pub fn frame(&self) -> &Frame {
192 &self.frame
193 }
194
195 pub fn iter(&self) -> impl Iterator<Item = &Frame> {
198 self.frame().iter_frames()
199 }
200
201 pub fn downcast_any_ref<T: Error + 'static>(&self) -> Option<&T> {
204 self.iter().find_map(|e| e.error.downcast_ref())
205 }
206}
207
208impl<E> Deref for Exn<E>
209where
210 E: Error + Send + Sync + 'static,
211{
212 type Target = E;
213
214 fn deref(&self) -> &Self::Target {
215 self.error()
216 }
217}
218
219impl<E: Error + Send + Sync + 'static> fmt::Debug for Exn<E> {
220 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
221 write_frame_recursive(f, self.frame(), "", ErrorMode::Display, TreeMode::Linearize)
222 }
223}
224
225impl fmt::Debug for Frame {
226 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
227 write_frame_recursive(f, self, "", ErrorMode::Display, TreeMode::Linearize)
228 }
229}
230
231#[derive(Copy, Clone)]
232enum ErrorMode {
233 Display,
234 Debug,
235}
236
237#[derive(Copy, Clone)]
238enum TreeMode {
239 Linearize,
240 Verbatim,
241}
242
243fn write_frame_recursive(
244 f: &mut fmt::Formatter<'_>,
245 frame: &Frame,
246 prefix: &str,
247 err_mode: ErrorMode,
248 tree_mode: TreeMode,
249) -> fmt::Result {
250 match err_mode {
251 ErrorMode::Display => fmt::Display::fmt(frame.error(), f),
252 ErrorMode::Debug => {
253 write!(f, "{:?}", frame.error())
254 }
255 }?;
256 if !f.alternate() {
257 write_location(f, frame.location)?;
258 }
259
260 let children = frame.children();
261 let children_len = children.len();
262
263 for (cidx, child) in children.iter().enumerate() {
264 write!(f, "\n{prefix}|")?;
265 write!(f, "\n{prefix}└─ ")?;
266
267 let child_child_len = child.children().len();
268 let may_linearize_chain = matches!(tree_mode, TreeMode::Linearize) && children_len == 1 && child_child_len == 1;
269 if may_linearize_chain {
270 write_frame_recursive(f, child, prefix, err_mode, tree_mode)?;
271 } else if cidx < children_len - 1 {
272 write_frame_recursive(f, child, &format!("{prefix}| "), err_mode, tree_mode)?;
273 } else {
274 write_frame_recursive(f, child, &format!("{prefix} "), err_mode, tree_mode)?;
275 }
276 }
277
278 Ok(())
279}
280
281impl<E: Error + Send + Sync + 'static> fmt::Display for Exn<E> {
282 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
283 fmt::Display::fmt(&self.frame, f)
284 }
285}
286
287impl fmt::Display for Frame {
288 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
289 if f.alternate() {
290 write_frame_recursive(f, self, "", ErrorMode::Debug, TreeMode::Verbatim)
292 } else {
293 fmt::Display::fmt(self.error(), f)
294 }
295 }
296}
297
298pub struct Frame {
300 error: Box<dyn Error + Send + Sync + 'static>,
302 location: &'static Location<'static>,
304 children: Vec<Frame>,
306}
307
308impl Frame {
309 pub fn error(&self) -> &(dyn Error + Send + Sync + 'static) {
311 &*self.error
312 }
313
314 pub fn location(&self) -> &'static Location<'static> {
316 self.location
317 }
318
319 pub fn children(&self) -> &[Frame] {
321 &self.children
322 }
323}
324
325impl Frame {
327 pub fn probable_cause(&self) -> Option<&Frame> {
334 fn walk<'a>(frame: &'a Frame, depth: usize) -> (usize, usize, &'a Frame) {
335 if frame.children.is_empty() {
336 return (1, depth, frame);
337 }
338
339 let mut total_leafs = 0;
340 let mut best: Option<(usize, usize, &'a Frame)> = None;
341
342 for child in &frame.children {
343 let (leafs, d, f) = walk(child, depth + 1);
344 total_leafs += leafs;
345
346 match best {
347 None => best = Some((leafs, d, f)),
348 Some((bl, bd, _)) => {
349 if leafs > bl || (leafs == bl && d > bd) {
350 best = Some((leafs, d, f));
351 }
352 }
353 }
354 }
355
356 let self_candidate = (total_leafs, depth, frame);
357 match best {
358 None => self_candidate,
359 Some(best_child) => {
360 if total_leafs > best_child.0 || (total_leafs == best_child.0 && depth > best_child.1) {
361 self_candidate
362 } else {
363 best_child
364 }
365 }
366 }
367 }
368
369 if self.children().iter().all(|c| c.children().is_empty()) {
372 if let Some(last) = self.children().last() {
373 return Some(last);
374 }
375 }
376
377 let res = walk(self, 0).2;
378 if std::ptr::addr_eq(res, self) {
379 None
380 } else {
381 Some(res)
382 }
383 }
384
385 pub fn iter_frames(&self) -> impl Iterator<Item = &Frame> + '_ {
388 let mut queue = std::collections::VecDeque::new();
389 queue.push_back(self);
390 BreadthFirstFrames { queue }
391 }
392}
393
394pub struct BreadthFirstFrames<'a> {
396 queue: std::collections::VecDeque<&'a Frame>,
397}
398
399impl<'a> Iterator for BreadthFirstFrames<'a> {
400 type Item = &'a Frame;
401
402 fn next(&mut self) -> Option<Self::Item> {
403 let frame = self.queue.pop_front()?;
404 for child in frame.children() {
405 self.queue.push_back(child);
406 }
407 Some(frame)
408 }
409}
410
411impl<E> From<Exn<E>> for Box<Frame>
412where
413 E: Error + Send + Sync + 'static,
414{
415 fn from(err: Exn<E>) -> Self {
416 err.frame
417 }
418}
419
420#[cfg(feature = "anyhow")]
421impl<E> From<Exn<E>> for anyhow::Error
422where
423 E: Error + Send + Sync + 'static,
424{
425 fn from(err: Exn<E>) -> Self {
426 anyhow::Error::from(err.into_chain())
427 }
428}
429
430impl<E> From<Exn<E>> for Frame
431where
432 E: Error + Send + Sync + 'static,
433{
434 fn from(err: Exn<E>) -> Self {
435 *err.frame
436 }
437}
438
439impl From<Frame> for Exn {
440 fn from(frame: Frame) -> Self {
441 Exn {
442 frame: Box::new(frame),
443 phantom: Default::default(),
444 }
445 }
446}
447
448pub struct Untyped(Box<dyn Error + Send + Sync + 'static>);
452
453impl fmt::Display for Untyped {
454 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
455 fmt::Display::fmt(&self.0, f)
456 }
457}
458
459impl fmt::Debug for Untyped {
460 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
461 fmt::Debug::fmt(&self.0, f)
462 }
463}
464
465impl Error for Untyped {}
466
467pub struct Something;
469
470impl fmt::Display for Something {
471 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
472 f.write_str("Something went wrong")
473 }
474}
475
476impl fmt::Debug for Something {
477 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
478 fmt::Display::fmt(&self, f)
479 }
480}
481
482impl Error for Something {}
483
484struct SourceError {
486 display: String,
487 alt_display: String,
488 debug: String,
489 alt_debug: String,
490}
491
492impl fmt::Debug for SourceError {
493 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
494 let dbg = if f.alternate() { &self.alt_debug } else { &self.debug };
495 f.write_str(dbg)
496 }
497}
498
499impl fmt::Display for SourceError {
500 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
501 let ds = if f.alternate() {
502 &self.alt_display
503 } else {
504 &self.display
505 };
506 f.write_str(ds)
507 }
508}
509
510impl Error for SourceError {}
511
512impl SourceError {
513 fn new(err: &dyn Error) -> Self {
514 SourceError {
515 display: err.to_string(),
516 alt_display: format!("{err:#}"),
517 debug: format!("{err:?}"),
518 alt_debug: format!("{err:#?}"),
519 }
520 }
521}
522
523impl<E> From<Exn<E>> for ChainedError
524where
525 E: std::error::Error + Send + Sync + 'static,
526{
527 fn from(mut err: Exn<E>) -> Self {
528 let stack: VecDeque<_> = err.frame.children.drain(..).collect();
529 let location = err.frame.location;
530 ChainedError {
531 err: err.into_box(),
532 location,
533 source: recurse_source_frames(stack),
534 }
535 }
536}
537
538fn recurse_source_frames(mut stack: VecDeque<Frame>) -> Option<Box<ChainedError>> {
539 let frame = stack.pop_front()?;
540 stack.extend(frame.children);
541 Box::new(ChainedError {
542 err: frame.error,
543 location: frame.location,
544 source: recurse_source_frames(stack),
545 })
546 .into()
547}