Skip to main content

aranya_util/
error.rs

1use std::{
2    error::Error,
3    fmt::{self, Display, Write},
4};
5
6/// Extension trait for formatting an error with source chain.
7pub trait ReportExt {
8    /// Display this error with source chain.
9    fn report(&self) -> impl Display;
10}
11
12impl<E> ReportExt for E
13where
14    E: Error,
15{
16    fn report(&self) -> impl Display {
17        ReportImpl(self)
18    }
19}
20
21// Implementation taken from `anyhow`.
22
23struct ReportImpl<E>(E);
24
25impl<E: Error> Display for ReportImpl<E> {
26    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
27        let error = &self.0;
28
29        write!(f, "{error}")?;
30
31        if let Some(cause) = error.source() {
32            write!(f, "\n\nCaused by:")?;
33            let multiple = cause.source().is_some();
34            for (n, error) in anyhow::Chain::new(cause).enumerate() {
35                writeln!(f)?;
36                let mut indented = Indented {
37                    inner: f,
38                    number: multiple.then_some(n),
39                    started: false,
40                };
41                write!(indented, "{error}")?;
42            }
43        }
44
45        Ok(())
46    }
47}
48
49struct Indented<'a, D> {
50    inner: &'a mut D,
51    number: Option<usize>,
52    started: bool,
53}
54
55impl<T> Write for Indented<'_, T>
56where
57    T: Write,
58{
59    fn write_str(&mut self, s: &str) -> fmt::Result {
60        for (i, line) in s.split('\n').enumerate() {
61            if !self.started {
62                self.started = true;
63                match self.number {
64                    Some(number) => write!(self.inner, "{number: >5}: ")?,
65                    None => self.inner.write_str("    ")?,
66                }
67            } else if i > 0 {
68                self.inner.write_char('\n')?;
69                if self.number.is_some() {
70                    self.inner.write_str("       ")?;
71                } else {
72                    self.inner.write_str("    ")?;
73                }
74            }
75
76            self.inner.write_str(line)?;
77        }
78
79        Ok(())
80    }
81}