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::{Metadata, types::ChainedError, write_location};
24
25pub struct Exn<E: std::error::Error + Send + Sync + 'static = Untyped> {
74 frame: Box<Frame>,
76 phantom: PhantomData<E>,
77}
78
79impl<E: Error + Send + Sync + 'static> From<E> for Exn<E> {
80 #[track_caller]
81 fn from(error: E) -> Self {
82 Exn::new(error)
83 }
84}
85
86impl<E: Error + Send + Sync + 'static> Exn<E> {
87 #[track_caller]
94 pub fn new(error: E) -> Self {
95 let frame = Frame {
96 error: Box::new(error),
97 location: Location::caller(),
98 children: Vec::new(),
99 };
100
101 Self {
102 frame: Box::new(frame),
103 phantom: PhantomData,
104 }
105 }
106
107 #[track_caller]
109 pub fn raise_all<T, I>(children: I, err: E) -> Self
110 where
111 T: Error + Send + Sync + 'static,
112 I: IntoIterator,
113 I::Item: Into<Exn<T>>,
114 {
115 let mut new_exn = Exn::new(err);
116 for exn in children {
117 let exn = exn.into();
118 new_exn.frame.children.push(*exn.frame);
119 }
120 new_exn
121 }
122
123 #[track_caller]
125 pub fn raise<T: Error + Send + Sync + 'static>(self, err: T) -> Exn<T> {
126 let mut new_exn = Exn::new(err);
127 new_exn.frame.children.push(*self.frame);
128 new_exn
129 }
130
131 #[track_caller]
133 pub fn chain<T: Error + Send + Sync + 'static>(mut self, err: impl Into<Exn<T>>) -> Exn<E> {
134 let err = err.into();
135 self.frame.children.push(*err.frame);
136 self
137 }
138
139 #[track_caller]
141 pub fn chain_all<T, I>(mut self, errors: I) -> Exn<E>
142 where
143 T: Error + Send + Sync + 'static,
144 I: IntoIterator,
145 I::Item: Into<Exn<T>>,
146 {
147 for err in errors {
148 let err = err.into();
149 self.frame.children.push(*err.frame);
150 }
151 self
152 }
153
154 pub fn drain_children(&mut self) -> impl Iterator<Item = Exn> + '_ {
159 self.frame.children.drain(..).map(Exn::from)
160 }
161
162 pub fn erased(self) -> Exn {
164 let untyped_frame = {
165 let Frame {
166 error,
167 location,
168 children,
169 } = *self.frame;
170 let error = Untyped(error);
173 Frame {
174 error: Box::new(error),
175 location,
176 children,
177 }
178 };
179 Exn {
180 frame: Box::new(untyped_frame),
181 phantom: Default::default(),
182 }
183 }
184
185 pub fn error(&self) -> &E {
187 self.frame
188 .error
189 .downcast_ref()
190 .expect("the owned frame always matches the compile-time error type")
191 }
192
193 pub fn into_box(self) -> Box<E> {
198 match self.frame.error.downcast() {
199 Ok(err) => err,
200 Err(_) => unreachable!("The type in the frame is always the type of this instance"),
201 }
202 }
203
204 pub fn into_inner(self) -> E {
209 *self.into_box()
210 }
211
212 pub fn into_error(self) -> crate::Error {
216 self.into()
217 }
218
219 pub fn into_chain(self) -> ChainedError {
224 self.into()
225 }
226
227 pub fn frame(&self) -> &Frame {
229 &self.frame
230 }
231
232 pub fn iter(&self) -> impl Iterator<Item = &Frame> {
235 self.frame().iter_frames()
236 }
237
238 pub fn iter_errors(&self) -> impl Iterator<Item = &(dyn Error + 'static)> + '_ {
242 self.frame.iter_errors_with_locations().map(|source| source.error())
243 }
244
245 pub fn metadata(&self) -> impl Iterator<Item = &Metadata> + '_ {
252 self.iter_errors()
253 .filter_map(|error| error.downcast_ref::<crate::Message>())
254 .map(|error| &error.values)
255 .filter(|values| !values.is_empty())
256 }
257
258 pub fn probable_cause(&self) -> &(dyn Error + 'static) {
263 self.frame.probable_cause().unwrap_or_else(|| self.frame.error())
264 }
265
266 pub fn downcast_any_ref<T: Error + 'static>(&self) -> Option<&T> {
271 self.iter_errors().find_map(|error| error.downcast_ref())
272 }
273}
274
275impl<E> Deref for Exn<E>
276where
277 E: Error + Send + Sync + 'static,
278{
279 type Target = E;
280
281 fn deref(&self) -> &Self::Target {
282 self.error()
283 }
284}
285
286impl<E: Error + Send + Sync + 'static> fmt::Debug for Exn<E> {
287 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
288 write_frame_recursive(f, self.frame(), "", ErrorMode::Display, TreeMode::Linearize)
289 }
290}
291
292impl fmt::Debug for Frame {
293 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
294 write_frame_recursive(f, self, "", ErrorMode::Display, TreeMode::Linearize)
295 }
296}
297
298#[derive(Copy, Clone)]
299pub(crate) enum ErrorMode {
300 Display,
301 Debug,
302}
303
304impl ErrorMode {
305 pub(crate) fn fmt(self, error: &(dyn Error + 'static), f: &mut fmt::Formatter<'_>) -> fmt::Result {
306 if let Some(io) = error.downcast_ref::<std::io::Error>()
307 && io.get_ref().is_some()
308 {
309 return write!(f, "I/O error ({:?})", io.kind());
311 }
312 match self {
314 ErrorMode::Display => write!(f, "{error}"),
315 ErrorMode::Debug => write!(f, "{error:?}"),
316 }
317 }
318}
319
320#[derive(Copy, Clone)]
321enum TreeMode {
322 Linearize,
323 Verbatim,
324}
325
326fn write_frame_recursive(
327 f: &mut fmt::Formatter<'_>,
328 frame: &Frame,
329 prefix: &str,
330 err_mode: ErrorMode,
331 tree_mode: TreeMode,
332) -> fmt::Result {
333 if crate::error::is_transparent_marker(frame.error()) {
334 let children = ErrorNode::Frame(frame).children();
335 if !children.is_empty() {
336 for (index, child) in children.into_iter().enumerate() {
337 if index != 0 {
338 writeln!(f)?;
339 }
340 write_error_node_recursive(f, child, prefix, err_mode, tree_mode)?;
341 }
342 return Ok(());
343 }
344 }
345 write_error_node_recursive(f, ErrorNode::Frame(frame), prefix, err_mode, tree_mode)
346}
347
348fn write_error_node_recursive(
349 f: &mut fmt::Formatter<'_>,
350 node: ErrorNode<'_>,
351 prefix: &str,
352 err_mode: ErrorMode,
353 tree_mode: TreeMode,
354) -> fmt::Result {
355 let mut root_error = node.error();
356 while let Some(error) = root_error.downcast_ref::<crate::Error>() {
357 root_error = error.error();
358 }
359 err_mode.fmt(root_error, f)?;
360 if !f.alternate() {
361 write_location(f, node.location())?;
362 }
363
364 if let Some(err) = node.error().downcast_ref::<crate::Error>() {
365 let mut skipped_root = false;
366 for source in err
367 .iter_errors_with_locations()
368 .filter(|source| !source.error().is::<crate::Error>())
369 {
370 if !skipped_root && std::ptr::eq(source.error(), root_error) {
372 skipped_root = true;
373 continue;
374 }
375 write!(f, "\n{prefix}|\n{prefix}└─ ")?;
376 err_mode.fmt(source.error(), f)?;
377 if !f.alternate() {
378 write_location(f, source.location().unwrap_or_else(|| node.location()))?;
379 }
380 }
381 }
382
383 let children = node.children();
384 let children_len = children.len();
385
386 for (child_index, child) in children.into_iter().enumerate() {
387 write!(f, "\n{prefix}|")?;
388 write!(f, "\n{prefix}└─ ")?;
389
390 let child_child_len = if child
391 .error()
392 .downcast_ref::<crate::Error>()
393 .is_some_and(|err| err.iter_errors().filter(|source| !source.is::<crate::Error>()).count() > 1)
394 {
395 1
396 } else {
397 child.children().len()
398 };
399 let may_linearize_chain = matches!(tree_mode, TreeMode::Linearize) && children_len == 1 && child_child_len == 1;
400 if may_linearize_chain {
401 write_error_node_recursive(f, child, prefix, err_mode, tree_mode)?;
402 } else if child_index < children_len - 1 {
403 write_error_node_recursive(f, child, &format!("{prefix}| "), err_mode, tree_mode)?;
404 } else {
405 write_error_node_recursive(f, child, &format!("{prefix} "), err_mode, tree_mode)?;
406 }
407 }
408
409 Ok(())
410}
411
412impl<E: Error + Send + Sync + 'static> fmt::Display for Exn<E> {
413 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
414 fmt::Display::fmt(&self.frame, f)
415 }
416}
417
418impl<E: Error + Send + Sync + 'static> PartialEq<str> for Exn<E> {
419 fn eq(&self, other: &str) -> bool {
420 crate::root_error_eq(self.frame().error(), other)
421 }
422}
423
424impl<E: Error + Send + Sync + 'static> PartialEq<&str> for Exn<E> {
425 fn eq(&self, other: &&str) -> bool {
426 <Self as PartialEq<str>>::eq(self, other)
427 }
428}
429
430impl<E: Error + Send + Sync + 'static> PartialEq<String> for Exn<E> {
431 fn eq(&self, other: &String) -> bool {
432 <Self as PartialEq<str>>::eq(self, other)
433 }
434}
435
436impl fmt::Display for Frame {
437 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
438 if f.alternate() {
439 write_frame_recursive(f, self, "", ErrorMode::Debug, TreeMode::Verbatim)
441 } else {
442 if crate::error::is_transparent_marker(self.error())
443 && let Some(diagnostic) = self.iter_errors_with_locations().next()
444 {
445 return fmt::Display::fmt(diagnostic.error(), f);
446 }
447 fmt::Display::fmt(self.error(), f)
448 }
449 }
450}
451
452pub struct Frame {
454 error: Box<dyn Error + Send + Sync + 'static>,
456 location: &'static Location<'static>,
458 children: Vec<Frame>,
460}
461
462impl Frame {
463 pub fn error(&self) -> &(dyn Error + Send + Sync + 'static) {
468 let mut error = &*self.error;
469 while let Some(erased) = error.downcast_ref::<Untyped>() {
470 error = &*erased.0;
471 }
472 error
473 }
474
475 pub fn location(&self) -> &'static Location<'static> {
477 self.location
478 }
479
480 pub fn children(&self) -> &[Frame] {
485 &self.children
486 }
487}
488
489#[derive(Clone, Copy)]
495pub(crate) enum ErrorNode<'a> {
496 Frame(&'a Frame),
497 Source {
498 error: &'a (dyn Error + 'static),
499 location: &'static Location<'static>,
500 },
501 FlatSource {
503 error: &'a (dyn Error + 'static),
504 location: &'static Location<'static>,
505 },
506}
507
508impl<'a> ErrorNode<'a> {
509 pub(crate) fn error(self) -> &'a (dyn Error + 'static) {
510 match self {
511 ErrorNode::Frame(frame) => frame.error(),
512 ErrorNode::Source { error, .. } | ErrorNode::FlatSource { error, .. } => error,
513 }
514 }
515
516 pub(crate) fn location(self) -> &'static Location<'static> {
521 match self {
522 ErrorNode::Frame(frame) => frame.location,
523 ErrorNode::Source { location, .. } | ErrorNode::FlatSource { location, .. } => location,
524 }
525 }
526
527 pub(crate) fn children(self) -> Vec<ErrorNode<'a>> {
534 if matches!(self, ErrorNode::FlatSource { .. }) {
535 return Vec::new();
536 }
537 let error = self.error();
538 let location = self.location();
539 let mut children = Vec::new();
540 if let Some(nested) = error.downcast_ref::<crate::Error>() {
541 if crate::error::is_transparent_marker(error) {
542 children.extend(
543 nested
544 .iter_errors_with_locations()
545 .filter(|source| !source.error().is::<crate::Error>())
546 .map(|source| ErrorNode::FlatSource {
547 error: source.error(),
548 location: source.location().unwrap_or(location),
549 }),
550 );
551 }
552 } else if let Some(error) = crate::error::native_source(error) {
553 children.push(ErrorNode::Source { error, location });
554 }
555 if let ErrorNode::Frame(frame) = self {
556 children.extend(frame.children.iter().map(ErrorNode::Frame));
557 }
558 let mut diagnostics = Vec::new();
559 for child in children {
560 if crate::error::is_transparent_marker(child.error()) {
561 diagnostics.extend(child.children());
562 } else {
563 diagnostics.push(child);
564 }
565 }
566 diagnostics
567 }
568}
569
570impl Frame {
572 pub fn probable_cause(&self) -> Option<&(dyn Error + 'static)> {
594 self.probable_cause_inner()
595 }
596
597 pub fn iter_frames(&self) -> impl Iterator<Item = &Frame> + '_ {
600 let mut queue = std::collections::VecDeque::new();
601 queue.push_back(self);
602 BreadthFirstFrames { queue }
603 }
604}
605
606pub struct BreadthFirstFrames<'a> {
608 queue: std::collections::VecDeque<&'a Frame>,
609}
610
611impl<'a> Iterator for BreadthFirstFrames<'a> {
612 type Item = &'a Frame;
613
614 fn next(&mut self) -> Option<Self::Item> {
615 let frame = self.queue.pop_front()?;
616 for child in frame.children() {
617 self.queue.push_back(child);
618 }
619 Some(frame)
620 }
621}
622
623impl<E> From<Exn<E>> for Box<Frame>
624where
625 E: Error + Send + Sync + 'static,
626{
627 fn from(err: Exn<E>) -> Self {
628 err.frame
629 }
630}
631
632impl<E> From<Exn<E>> for Box<dyn Error + Send + Sync + 'static>
633where
634 E: Error + Send + Sync + 'static,
635{
636 fn from(err: Exn<E>) -> Self {
637 Box::new(err.into_error())
638 }
639}
640
641#[cfg(feature = "anyhow")]
642impl<E> From<Exn<E>> for anyhow::Error
643where
644 E: Error + Send + Sync + 'static,
645{
646 fn from(err: Exn<E>) -> Self {
647 anyhow::Error::from(err.into_chain())
648 }
649}
650
651impl<E> From<Exn<E>> for Frame
652where
653 E: Error + Send + Sync + 'static,
654{
655 fn from(err: Exn<E>) -> Self {
656 *err.frame
657 }
658}
659
660impl From<Frame> for Exn {
661 fn from(mut frame: Frame) -> Self {
662 if !frame.error.is::<Untyped>() {
663 frame.error = Box::new(Untyped(frame.error));
664 }
665 Exn {
666 frame: Box::new(frame),
667 phantom: Default::default(),
668 }
669 }
670}
671
672pub struct Untyped(Box<dyn Error + Send + Sync + 'static>);
676
677impl Untyped {
678 pub(crate) fn from_boxed(error: Box<dyn Error + Send + Sync + 'static>) -> Self {
679 Untyped(error)
680 }
681}
682
683impl fmt::Display for Untyped {
684 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
685 fmt::Display::fmt(&self.0, f)
686 }
687}
688
689impl fmt::Debug for Untyped {
690 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
691 fmt::Debug::fmt(&self.0, f)
692 }
693}
694
695impl Error for Untyped {
696 fn source(&self) -> Option<&(dyn Error + 'static)> {
697 self.0.source()
698 }
699}
700
701impl<E> From<Exn<E>> for ChainedError
702where
703 E: std::error::Error + Send + Sync + 'static,
704{
705 fn from(err: Exn<E>) -> Self {
706 let flattened = flatten_error_nodes(*err.frame);
707 let mut source = None;
708 for node in flattened.into_iter().rev() {
709 source = Some(Box::new(ChainedError {
710 err: node.error,
711 location: node.location,
712 logical_parent: node.logical_parent,
713 source,
714 }));
715 }
716 *source.expect("an Exn always contains its root error")
717 }
718}
719
720struct OwnedErrorNode {
721 error: ErrorHandle,
722 location: &'static Location<'static>,
723 logical_parent: Option<usize>,
724}
725
726fn flatten_error_nodes(root: Frame) -> Vec<OwnedErrorNode> {
736 enum Pending {
737 Frame {
738 frame: Frame,
739 logical_parent: Option<usize>,
740 },
741 Source {
742 error: ErrorHandle,
743 location: &'static Location<'static>,
744 logical_parent: usize,
745 },
746 }
747
748 let mut queue = VecDeque::from([Pending::Frame {
749 frame: root,
750 logical_parent: None,
751 }]);
752 let mut out = Vec::new();
753 while let Some(node) = queue.pop_front() {
754 let node_index = out.len();
755 match node {
756 Pending::Frame {
757 frame:
758 Frame {
759 error,
760 location,
761 children,
762 },
763 logical_parent,
764 } => {
765 let error = ErrorHandle::new(unerase(error));
766 if !error.error().is::<crate::Error>()
767 && let Some(source) = error.source()
768 {
769 queue.push_back(Pending::Source {
770 error: source,
771 location,
772 logical_parent: node_index,
773 });
774 }
775 queue.extend(children.into_iter().map(|frame| Pending::Frame {
776 frame,
777 logical_parent: Some(node_index),
778 }));
779 out.push(OwnedErrorNode {
780 error,
781 location,
782 logical_parent,
783 });
784 }
785 Pending::Source {
786 error,
787 location,
788 logical_parent,
789 } => {
790 if !error.error().is::<crate::Error>()
791 && let Some(source) = error.source()
792 {
793 queue.push_back(Pending::Source {
794 error: source,
795 location,
796 logical_parent: node_index,
797 });
798 }
799 out.push(OwnedErrorNode {
800 error,
801 location,
802 logical_parent: Some(logical_parent),
803 });
804 }
805 }
806 }
807 out
808}
809
810fn unerase(mut error: Box<dyn Error + Send + Sync + 'static>) -> Box<dyn Error + Send + Sync + 'static> {
817 loop {
818 match error.downcast::<Untyped>() {
819 Ok(untyped) => error = untyped.0,
820 Err(typed) => return typed,
821 }
822 }
823}