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 fmt::Display for Frame {
294 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
295 if f.alternate() {
296 write_frame_recursive(f, self, "", ErrorMode::Debug, TreeMode::Verbatim)
298 } else {
299 fmt::Display::fmt(self.error(), f)
300 }
301 }
302}
303
304pub struct Frame {
306 error: Box<dyn Error + Send + Sync + 'static>,
308 location: &'static Location<'static>,
310 children: Vec<Frame>,
312}
313
314impl Frame {
315 pub fn error(&self) -> &(dyn Error + Send + Sync + 'static) {
320 let mut error = &*self.error;
321 while let Some(erased) = error.downcast_ref::<Untyped>() {
322 error = &*erased.0;
323 }
324 error
325 }
326
327 pub fn location(self) -> &'static Location<'static> {
334 self.location
335 }
336
337 pub fn children(&self) -> &[Frame] {
342 &self.children
343 }
344}
345
346#[derive(Clone, Copy)]
352pub(crate) enum ErrorNode<'a> {
353 Frame(&'a Frame),
354 Source {
355 error: &'a (dyn Error + 'static),
356 location: &'static Location<'static>,
357 },
358}
359
360impl<'a> ErrorNode<'a> {
361 pub(crate) fn error(self) -> &'a (dyn Error + 'static) {
362 match self {
363 ErrorNode::Frame(frame) => frame.error(),
364 ErrorNode::Source { error, .. } => error,
365 }
366 }
367
368 pub(crate) fn location(self) -> &'static Location<'static> {
374 match self {
375 ErrorNode::Frame(frame) => frame.location,
376 ErrorNode::Source { location, .. } => location,
377 }
378 }
379
380 #[cfg(any(feature = "tree-error", not(feature = "auto-chain-error")))]
385 pub(crate) fn captured_location(self) -> Option<&'static Location<'static>> {
386 match self {
387 ErrorNode::Frame(frame) => Some(frame.location),
388 ErrorNode::Source { .. } => None,
389 }
390 }
391
392 pub(crate) fn children(self) -> Vec<ErrorNode<'a>> {
399 let error = self.error();
400 let location = self.location();
401 let mut children = Vec::new();
402 if !error.is::<crate::Error>() {
403 if let Some(error) = error.source() {
404 children.push(ErrorNode::Source { error, location });
405 }
406 }
407 if let ErrorNode::Frame(frame) = self {
408 children.extend(frame.children.iter().map(ErrorNode::Frame));
409 }
410 children
411 }
412
413 fn same(self, other: ErrorNode<'_>) -> bool {
414 std::ptr::addr_eq(self.error(), other.error())
415 }
416}
417
418impl Frame {
420 pub fn probable_cause(&self) -> Option<&(dyn Error + 'static)> {
427 self.probable_cause_node().map(ErrorNode::error)
428 }
429
430 pub(crate) fn probable_cause_node(&self) -> Option<ErrorNode<'_>> {
431 fn walk(node: ErrorNode<'_>, depth: usize) -> (usize, usize, ErrorNode<'_>) {
438 let children = node.children();
439 if children.is_empty() {
440 return (1, depth, node);
441 }
442
443 let mut total_leafs = 0;
444 let mut best: Option<(usize, usize, ErrorNode<'_>)> = None;
445
446 for child in children {
447 let (leafs, child_depth, candidate) = walk(child, depth + 1);
448 total_leafs += leafs;
449
450 match best {
451 None => best = Some((leafs, child_depth, candidate)),
452 Some((best_leafs, best_depth, _)) => {
453 if leafs > best_leafs || (leafs == best_leafs && child_depth > best_depth) {
454 best = Some((leafs, child_depth, candidate));
455 }
456 }
457 }
458 }
459
460 let self_candidate = (total_leafs, depth, node);
461 match best {
462 None => self_candidate,
463 Some(best_child) => {
464 if total_leafs > best_child.0 || (total_leafs == best_child.0 && depth > best_child.1) {
465 self_candidate
466 } else {
467 best_child
468 }
469 }
470 }
471 }
472
473 let root = ErrorNode::Frame(self);
474 let children = root.children();
475 if children.iter().all(|child| child.children().is_empty()) {
476 if let Some(last) = children.last() {
477 return Some(*last);
478 }
479 }
480
481 let cause = walk(root, 0).2;
482 (!cause.same(root)).then_some(cause)
483 }
484
485 pub fn iter_frames(&self) -> impl Iterator<Item = &Frame> + '_ {
488 let mut queue = std::collections::VecDeque::new();
489 queue.push_back(self);
490 BreadthFirstFrames { queue }
491 }
492
493 pub(crate) fn iter_error_nodes(&self) -> BreadthFirstErrorNodes<'_> {
494 let mut queue = VecDeque::new();
495 queue.push_back(ErrorNode::Frame(self));
496 BreadthFirstErrorNodes { queue }
497 }
498}
499
500pub struct BreadthFirstFrames<'a> {
502 queue: std::collections::VecDeque<&'a Frame>,
503}
504
505impl<'a> Iterator for BreadthFirstFrames<'a> {
506 type Item = &'a Frame;
507
508 fn next(&mut self) -> Option<Self::Item> {
509 let frame = self.queue.pop_front()?;
510 for child in frame.children() {
511 self.queue.push_back(child);
512 }
513 Some(frame)
514 }
515}
516
517pub(crate) struct BreadthFirstErrorNodes<'a> {
518 queue: VecDeque<ErrorNode<'a>>,
519}
520
521impl<'a> Iterator for BreadthFirstErrorNodes<'a> {
522 type Item = ErrorNode<'a>;
523
524 fn next(&mut self) -> Option<Self::Item> {
525 let node = self.queue.pop_front()?;
526 self.queue.extend(node.children());
527 Some(node)
528 }
529}
530
531impl<E> From<Exn<E>> for Box<Frame>
532where
533 E: Error + Send + Sync + 'static,
534{
535 fn from(err: Exn<E>) -> Self {
536 err.frame
537 }
538}
539
540impl<E> From<Exn<E>> for Box<dyn Error + Send + Sync + 'static>
541where
542 E: Error + Send + Sync + 'static,
543{
544 fn from(err: Exn<E>) -> Self {
545 Box::new(err.into_error())
546 }
547}
548
549#[cfg(feature = "anyhow")]
550impl<E> From<Exn<E>> for anyhow::Error
551where
552 E: Error + Send + Sync + 'static,
553{
554 fn from(err: Exn<E>) -> Self {
555 anyhow::Error::from(err.into_chain())
556 }
557}
558
559impl<E> From<Exn<E>> for Frame
560where
561 E: Error + Send + Sync + 'static,
562{
563 fn from(err: Exn<E>) -> Self {
564 *err.frame
565 }
566}
567
568impl From<Frame> for Exn {
569 fn from(frame: Frame) -> Self {
570 Exn {
571 frame: Box::new(frame),
572 phantom: Default::default(),
573 }
574 }
575}
576
577pub struct Untyped(Box<dyn Error + Send + Sync + 'static>);
581
582impl Untyped {
583 pub(crate) fn from_boxed(error: Box<dyn Error + Send + Sync + 'static>) -> Self {
584 Untyped(error)
585 }
586}
587
588impl fmt::Display for Untyped {
589 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
590 fmt::Display::fmt(&self.0, f)
591 }
592}
593
594impl fmt::Debug for Untyped {
595 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
596 fmt::Debug::fmt(&self.0, f)
597 }
598}
599
600impl Error for Untyped {
601 fn source(&self) -> Option<&(dyn Error + 'static)> {
602 self.0.source()
603 }
604}
605
606pub struct Something;
608
609impl fmt::Display for Something {
610 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
611 f.write_str("Something went wrong")
612 }
613}
614
615impl fmt::Debug for Something {
616 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
617 fmt::Display::fmt(&self, f)
618 }
619}
620
621impl Error for Something {}
622
623impl<E> From<Exn<E>> for ChainedError
624where
625 E: std::error::Error + Send + Sync + 'static,
626{
627 fn from(err: Exn<E>) -> Self {
628 let probable_cause = err
629 .frame
630 .probable_cause_node()
631 .and_then(|cause| err.frame.iter_error_nodes().position(|node| node.same(cause)));
632 let flattened = flatten_error_nodes(*err.frame);
633 let mut source = None;
634 let leaves_to_root = flattened.into_iter().enumerate().rev();
635 for (index, node) in leaves_to_root {
636 source = Some(Box::new(ChainedError {
637 err: node.error,
638 location: node.location,
639 is_probable_cause: probable_cause.map_or(index == 0, |cause| cause == index),
640 logical_parent: node.logical_parent,
641 source,
642 }));
643 }
644 *source.expect("an Exn always contains its root error")
645 }
646}
647
648struct OwnedErrorNode {
649 error: ErrorHandle,
650 location: &'static Location<'static>,
651 logical_parent: Option<usize>,
652}
653
654fn flatten_error_nodes(root: Frame) -> Vec<OwnedErrorNode> {
664 enum Pending {
665 Frame {
666 frame: Frame,
667 logical_parent: Option<usize>,
668 },
669 Source {
670 error: ErrorHandle,
671 location: &'static Location<'static>,
672 logical_parent: usize,
673 },
674 }
675
676 let mut queue = VecDeque::from([Pending::Frame {
677 frame: root,
678 logical_parent: None,
679 }]);
680 let mut out = Vec::new();
681 while let Some(node) = queue.pop_front() {
682 let node_index = out.len();
683 match node {
684 Pending::Frame {
685 frame:
686 Frame {
687 error,
688 location,
689 children,
690 },
691 logical_parent,
692 } => {
693 let error = ErrorHandle::new(unerase(error));
694 if !error.error().is::<crate::Error>() {
695 if let Some(source) = error.source() {
696 queue.push_back(Pending::Source {
697 error: source,
698 location,
699 logical_parent: node_index,
700 });
701 }
702 }
703 queue.extend(children.into_iter().map(|frame| Pending::Frame {
704 frame,
705 logical_parent: Some(node_index),
706 }));
707 out.push(OwnedErrorNode {
708 error,
709 location,
710 logical_parent,
711 });
712 }
713 Pending::Source {
714 error,
715 location,
716 logical_parent,
717 } => {
718 if !error.error().is::<crate::Error>() {
719 if let Some(source) = error.source() {
720 queue.push_back(Pending::Source {
721 error: source,
722 location,
723 logical_parent: node_index,
724 });
725 }
726 }
727 out.push(OwnedErrorNode {
728 error,
729 location,
730 logical_parent: Some(logical_parent),
731 });
732 }
733 }
734 }
735 out
736}
737
738fn unerase(mut error: Box<dyn Error + Send + Sync + 'static>) -> Box<dyn Error + Send + Sync + 'static> {
745 loop {
746 match error.downcast::<Untyped>() {
747 Ok(untyped) => error = untyped.0,
748 Err(typed) => return typed,
749 }
750 }
751}