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::concrete::chain::ErrorHandle;
23use crate::{ChainedError, Exn, write_location};
24
25impl<E: Error + Send + Sync + 'static> From<E> for Exn<E> {
26 #[track_caller]
27 fn from(error: E) -> Self {
28 Exn::new(error)
29 }
30}
31
32impl<E: Error + Send + Sync + 'static> Exn<E> {
33 #[track_caller]
40 pub fn new(error: E) -> Self {
41 let frame = Frame {
42 error: Box::new(error),
43 location: Location::caller(),
44 children: Vec::new(),
45 };
46
47 Self {
48 frame: Box::new(frame),
49 phantom: PhantomData,
50 }
51 }
52
53 #[track_caller]
55 pub fn raise_all<T, I>(children: I, err: E) -> Self
56 where
57 T: Error + Send + Sync + 'static,
58 I: IntoIterator,
59 I::Item: Into<Exn<T>>,
60 {
61 let mut new_exn = Exn::new(err);
62 for exn in children {
63 let exn = exn.into();
64 new_exn.frame.children.push(*exn.frame);
65 }
66 new_exn
67 }
68
69 #[track_caller]
71 pub fn raise<T: Error + Send + Sync + 'static>(self, err: T) -> Exn<T> {
72 let mut new_exn = Exn::new(err);
73 new_exn.frame.children.push(*self.frame);
74 new_exn
75 }
76
77 #[track_caller]
79 pub fn chain<T: Error + Send + Sync + 'static>(mut self, err: impl Into<Exn<T>>) -> Exn<E> {
80 let err = err.into();
81 self.frame.children.push(*err.frame);
82 self
83 }
84
85 #[track_caller]
87 pub fn chain_all<T, I>(mut self, errors: I) -> Exn<E>
88 where
89 T: Error + Send + Sync + 'static,
90 I: IntoIterator,
91 I::Item: Into<Exn<T>>,
92 {
93 for err in errors {
94 let err = err.into();
95 self.frame.children.push(*err.frame);
96 }
97 self
98 }
99
100 pub fn drain_children(&mut self) -> impl Iterator<Item = Exn> + '_ {
105 self.frame.children.drain(..).map(Exn::from)
106 }
107
108 pub fn erased(self) -> Exn {
110 let untyped_frame = {
111 let Frame {
112 error,
113 location,
114 children,
115 } = *self.frame;
116 let error = Untyped(error);
119 Frame {
120 error: Box::new(error),
121 location,
122 children,
123 }
124 };
125 Exn {
126 frame: Box::new(untyped_frame),
127 phantom: Default::default(),
128 }
129 }
130
131 pub fn error(&self) -> &E {
133 self.frame
134 .error
135 .downcast_ref()
136 .expect("the owned frame always matches the compile-time error type")
137 }
138
139 pub fn into_box(self) -> Box<E> {
144 match self.frame.error.downcast() {
145 Ok(err) => err,
146 Err(_) => unreachable!("The type in the frame is always the type of this instance"),
147 }
148 }
149
150 pub fn into_inner(self) -> E {
155 *self.into_box()
156 }
157
158 pub fn into_error(self) -> crate::Error {
162 self.into()
163 }
164
165 pub fn into_chain(self) -> crate::ChainedError {
170 self.into()
171 }
172
173 pub fn frame(&self) -> &Frame {
175 &self.frame
176 }
177
178 pub fn iter(&self) -> impl Iterator<Item = &Frame> {
181 self.frame().iter_frames()
182 }
183
184 pub fn downcast_any_ref<T: Error + 'static>(&self) -> Option<&T> {
186 self.frame
187 .iter_error_nodes()
188 .find_map(|node| node.error().downcast_ref())
189 }
190}
191
192impl<E> Deref for Exn<E>
193where
194 E: Error + Send + Sync + 'static,
195{
196 type Target = E;
197
198 fn deref(&self) -> &Self::Target {
199 self.error()
200 }
201}
202
203impl<E: Error + Send + Sync + 'static> fmt::Debug for Exn<E> {
204 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
205 write_frame_recursive(f, self.frame(), "", ErrorMode::Display, TreeMode::Linearize)
206 }
207}
208
209impl fmt::Debug for Frame {
210 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
211 write_frame_recursive(f, self, "", ErrorMode::Display, TreeMode::Linearize)
212 }
213}
214
215#[derive(Copy, Clone)]
216enum ErrorMode {
217 Display,
218 Debug,
219}
220
221#[derive(Copy, Clone)]
222enum TreeMode {
223 Linearize,
224 Verbatim,
225}
226
227fn write_frame_recursive(
228 f: &mut fmt::Formatter<'_>,
229 frame: &Frame,
230 prefix: &str,
231 err_mode: ErrorMode,
232 tree_mode: TreeMode,
233) -> fmt::Result {
234 write_error_node_recursive(f, ErrorNode::Frame(frame), prefix, err_mode, tree_mode)
235}
236
237fn write_error_node_recursive(
238 f: &mut fmt::Formatter<'_>,
239 node: ErrorNode<'_>,
240 prefix: &str,
241 err_mode: ErrorMode,
242 tree_mode: TreeMode,
243) -> fmt::Result {
244 match err_mode {
245 ErrorMode::Display => fmt::Display::fmt(node.error(), f),
246 ErrorMode::Debug => write!(f, "{:?}", node.error()),
247 }?;
248 if !f.alternate() {
249 write_location(f, node.location())?;
250 }
251
252 if let Some(err) = node.error().downcast_ref::<crate::Error>() {
253 for source in err.iter_errors().filter(|source| !source.is::<crate::Error>()).skip(1) {
254 write!(f, "\n{prefix}|\n{prefix}└─ {source}")?;
255 }
256 }
257
258 let children = node.children();
259 let children_len = children.len();
260
261 for (child_index, child) in children.into_iter().enumerate() {
262 write!(f, "\n{prefix}|")?;
263 write!(f, "\n{prefix}└─ ")?;
264
265 let child_child_len = if child
266 .error()
267 .downcast_ref::<crate::Error>()
268 .is_some_and(|err| err.iter_errors().filter(|source| !source.is::<crate::Error>()).count() > 1)
269 {
270 1
271 } else {
272 child.children().len()
273 };
274 let may_linearize_chain = matches!(tree_mode, TreeMode::Linearize) && children_len == 1 && child_child_len == 1;
275 if may_linearize_chain {
276 write_error_node_recursive(f, child, prefix, err_mode, tree_mode)?;
277 } else if child_index < children_len - 1 {
278 write_error_node_recursive(f, child, &format!("{prefix}| "), err_mode, tree_mode)?;
279 } else {
280 write_error_node_recursive(f, child, &format!("{prefix} "), err_mode, tree_mode)?;
281 }
282 }
283
284 Ok(())
285}
286
287impl<E: Error + Send + Sync + 'static> fmt::Display for Exn<E> {
288 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
289 fmt::Display::fmt(&self.frame, f)
290 }
291}
292
293impl<E: Error + Send + Sync + 'static> PartialEq<str> for Exn<E> {
294 fn eq(&self, other: &str) -> bool {
295 crate::root_error_eq(self.frame().error(), other)
296 }
297}
298
299impl<E: Error + Send + Sync + 'static> PartialEq<&str> for Exn<E> {
300 fn eq(&self, other: &&str) -> bool {
301 <Self as PartialEq<str>>::eq(self, other)
302 }
303}
304
305impl<E: Error + Send + Sync + 'static> PartialEq<String> for Exn<E> {
306 fn eq(&self, other: &String) -> bool {
307 <Self as PartialEq<str>>::eq(self, other)
308 }
309}
310
311impl fmt::Display for Frame {
312 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
313 if f.alternate() {
314 write_frame_recursive(f, self, "", ErrorMode::Debug, TreeMode::Verbatim)
316 } else {
317 fmt::Display::fmt(self.error(), f)
318 }
319 }
320}
321
322pub struct Frame {
324 error: Box<dyn Error + Send + Sync + 'static>,
326 location: &'static Location<'static>,
328 children: Vec<Frame>,
330}
331
332impl Frame {
333 pub fn error(&self) -> &(dyn Error + Send + Sync + 'static) {
338 let mut error = &*self.error;
339 while let Some(erased) = error.downcast_ref::<Untyped>() {
340 error = &*erased.0;
341 }
342 error
343 }
344
345 pub fn location(self) -> &'static Location<'static> {
352 self.location
353 }
354
355 pub fn children(&self) -> &[Frame] {
360 &self.children
361 }
362}
363
364#[derive(Clone, Copy)]
370pub(crate) enum ErrorNode<'a> {
371 Frame(&'a Frame),
372 Source {
373 error: &'a (dyn Error + 'static),
374 location: &'static Location<'static>,
375 },
376}
377
378impl<'a> ErrorNode<'a> {
379 pub(crate) fn error(self) -> &'a (dyn Error + 'static) {
380 match self {
381 ErrorNode::Frame(frame) => frame.error(),
382 ErrorNode::Source { error, .. } => error,
383 }
384 }
385
386 pub(crate) fn location(self) -> &'static Location<'static> {
392 match self {
393 ErrorNode::Frame(frame) => frame.location,
394 ErrorNode::Source { location, .. } => location,
395 }
396 }
397
398 #[cfg(any(feature = "tree-error", not(feature = "auto-chain-error")))]
403 pub(crate) fn captured_location(self) -> Option<&'static Location<'static>> {
404 match self {
405 ErrorNode::Frame(frame) => Some(frame.location),
406 ErrorNode::Source { .. } => None,
407 }
408 }
409
410 pub(crate) fn children(self) -> Vec<ErrorNode<'a>> {
417 let error = self.error();
418 let location = self.location();
419 let mut children = Vec::new();
420 if !error.is::<crate::Error>() {
421 if let Some(error) = error.source() {
422 children.push(ErrorNode::Source { error, location });
423 }
424 }
425 if let ErrorNode::Frame(frame) = self {
426 children.extend(frame.children.iter().map(ErrorNode::Frame));
427 }
428 children
429 }
430
431 fn same(self, other: ErrorNode<'_>) -> bool {
432 std::ptr::addr_eq(self.error(), other.error())
433 }
434}
435
436impl Frame {
438 pub fn probable_cause(&self) -> Option<&(dyn Error + 'static)> {
445 self.probable_cause_node().map(ErrorNode::error)
446 }
447
448 pub(crate) fn probable_cause_node(&self) -> Option<ErrorNode<'_>> {
449 fn walk(node: ErrorNode<'_>, depth: usize) -> (usize, usize, ErrorNode<'_>) {
456 let children = node.children();
457 if children.is_empty() {
458 return (1, depth, node);
459 }
460
461 let mut total_leafs = 0;
462 let mut best: Option<(usize, usize, ErrorNode<'_>)> = None;
463
464 for child in children {
465 let (leafs, child_depth, candidate) = walk(child, depth + 1);
466 total_leafs += leafs;
467
468 match best {
469 None => best = Some((leafs, child_depth, candidate)),
470 Some((best_leafs, best_depth, _)) => {
471 if leafs > best_leafs || (leafs == best_leafs && child_depth > best_depth) {
472 best = Some((leafs, child_depth, candidate));
473 }
474 }
475 }
476 }
477
478 let self_candidate = (total_leafs, depth, node);
479 match best {
480 None => self_candidate,
481 Some(best_child) => {
482 if total_leafs > best_child.0 || (total_leafs == best_child.0 && depth > best_child.1) {
483 self_candidate
484 } else {
485 best_child
486 }
487 }
488 }
489 }
490
491 let root = ErrorNode::Frame(self);
492 let children = root.children();
493 if children.iter().all(|child| child.children().is_empty()) {
494 if let Some(last) = children.last() {
495 return Some(*last);
496 }
497 }
498
499 let cause = walk(root, 0).2;
500 (!cause.same(root)).then_some(cause)
501 }
502
503 pub fn iter_frames(&self) -> impl Iterator<Item = &Frame> + '_ {
506 let mut queue = std::collections::VecDeque::new();
507 queue.push_back(self);
508 BreadthFirstFrames { queue }
509 }
510
511 pub(crate) fn iter_error_nodes(&self) -> BreadthFirstErrorNodes<'_> {
512 let mut queue = VecDeque::new();
513 queue.push_back(ErrorNode::Frame(self));
514 BreadthFirstErrorNodes { queue }
515 }
516}
517
518pub struct BreadthFirstFrames<'a> {
520 queue: std::collections::VecDeque<&'a Frame>,
521}
522
523impl<'a> Iterator for BreadthFirstFrames<'a> {
524 type Item = &'a Frame;
525
526 fn next(&mut self) -> Option<Self::Item> {
527 let frame = self.queue.pop_front()?;
528 for child in frame.children() {
529 self.queue.push_back(child);
530 }
531 Some(frame)
532 }
533}
534
535pub(crate) struct BreadthFirstErrorNodes<'a> {
536 queue: VecDeque<ErrorNode<'a>>,
537}
538
539impl<'a> Iterator for BreadthFirstErrorNodes<'a> {
540 type Item = ErrorNode<'a>;
541
542 fn next(&mut self) -> Option<Self::Item> {
543 let node = self.queue.pop_front()?;
544 self.queue.extend(node.children());
545 Some(node)
546 }
547}
548
549impl<E> From<Exn<E>> for Box<Frame>
550where
551 E: Error + Send + Sync + 'static,
552{
553 fn from(err: Exn<E>) -> Self {
554 err.frame
555 }
556}
557
558impl<E> From<Exn<E>> for Box<dyn Error + Send + Sync + 'static>
559where
560 E: Error + Send + Sync + 'static,
561{
562 fn from(err: Exn<E>) -> Self {
563 Box::new(err.into_error())
564 }
565}
566
567#[cfg(feature = "anyhow")]
568impl<E> From<Exn<E>> for anyhow::Error
569where
570 E: Error + Send + Sync + 'static,
571{
572 fn from(err: Exn<E>) -> Self {
573 anyhow::Error::from(err.into_chain())
574 }
575}
576
577impl<E> From<Exn<E>> for Frame
578where
579 E: Error + Send + Sync + 'static,
580{
581 fn from(err: Exn<E>) -> Self {
582 *err.frame
583 }
584}
585
586impl From<Frame> for Exn {
587 fn from(frame: Frame) -> Self {
588 Exn {
589 frame: Box::new(frame),
590 phantom: Default::default(),
591 }
592 }
593}
594
595pub struct Untyped(Box<dyn Error + Send + Sync + 'static>);
599
600impl Untyped {
601 pub(crate) fn from_boxed(error: Box<dyn Error + Send + Sync + 'static>) -> Self {
602 Untyped(error)
603 }
604}
605
606impl fmt::Display for Untyped {
607 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
608 fmt::Display::fmt(&self.0, f)
609 }
610}
611
612impl fmt::Debug for Untyped {
613 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
614 fmt::Debug::fmt(&self.0, f)
615 }
616}
617
618impl Error for Untyped {
619 fn source(&self) -> Option<&(dyn Error + 'static)> {
620 self.0.source()
621 }
622}
623
624pub struct Something;
626
627impl fmt::Display for Something {
628 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
629 f.write_str("Something went wrong")
630 }
631}
632
633impl fmt::Debug for Something {
634 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
635 fmt::Display::fmt(&self, f)
636 }
637}
638
639impl Error for Something {}
640
641impl<E> From<Exn<E>> for ChainedError
642where
643 E: std::error::Error + Send + Sync + 'static,
644{
645 fn from(err: Exn<E>) -> Self {
646 let probable_cause = err
647 .frame
648 .probable_cause_node()
649 .and_then(|cause| err.frame.iter_error_nodes().position(|node| node.same(cause)));
650 let flattened = flatten_error_nodes(*err.frame);
651 let mut source = None;
652 let leaves_to_root = flattened.into_iter().enumerate().rev();
653 for (index, node) in leaves_to_root {
654 source = Some(Box::new(ChainedError {
655 err: node.error,
656 location: node.location,
657 is_probable_cause: probable_cause.map_or(index == 0, |cause| cause == index),
658 logical_parent: node.logical_parent,
659 source,
660 }));
661 }
662 *source.expect("an Exn always contains its root error")
663 }
664}
665
666struct OwnedErrorNode {
667 error: ErrorHandle,
668 location: &'static Location<'static>,
669 logical_parent: Option<usize>,
670}
671
672fn flatten_error_nodes(root: Frame) -> Vec<OwnedErrorNode> {
682 enum Pending {
683 Frame {
684 frame: Frame,
685 logical_parent: Option<usize>,
686 },
687 Source {
688 error: ErrorHandle,
689 location: &'static Location<'static>,
690 logical_parent: usize,
691 },
692 }
693
694 let mut queue = VecDeque::from([Pending::Frame {
695 frame: root,
696 logical_parent: None,
697 }]);
698 let mut out = Vec::new();
699 while let Some(node) = queue.pop_front() {
700 let node_index = out.len();
701 match node {
702 Pending::Frame {
703 frame:
704 Frame {
705 error,
706 location,
707 children,
708 },
709 logical_parent,
710 } => {
711 let error = ErrorHandle::new(unerase(error));
712 if !error.error().is::<crate::Error>() {
713 if let Some(source) = error.source() {
714 queue.push_back(Pending::Source {
715 error: source,
716 location,
717 logical_parent: node_index,
718 });
719 }
720 }
721 queue.extend(children.into_iter().map(|frame| Pending::Frame {
722 frame,
723 logical_parent: Some(node_index),
724 }));
725 out.push(OwnedErrorNode {
726 error,
727 location,
728 logical_parent,
729 });
730 }
731 Pending::Source {
732 error,
733 location,
734 logical_parent,
735 } => {
736 if !error.error().is::<crate::Error>() {
737 if let Some(source) = error.source() {
738 queue.push_back(Pending::Source {
739 error: source,
740 location,
741 logical_parent: node_index,
742 });
743 }
744 }
745 out.push(OwnedErrorNode {
746 error,
747 location,
748 logical_parent: Some(logical_parent),
749 });
750 }
751 }
752 }
753 out
754}
755
756fn unerase(mut error: Box<dyn Error + Send + Sync + 'static>) -> Box<dyn Error + Send + Sync + 'static> {
763 loop {
764 match error.downcast::<Untyped>() {
765 Ok(untyped) => error = untyped.0,
766 Err(typed) => return typed,
767 }
768 }
769}