test_try/
lib.rs

1//! test-try.
2
3pub use test_try_macros::test_try;
4
5pub mod report {
6    //! This module is inspired from [std::error::Report].
7
8    use std::error::Error;
9    use std::fmt::Write;
10    use std::fmt::{self};
11    use std::sync::Arc;
12
13    /// Test report.
14    pub struct Report {
15        error: Arc<dyn std::error::Error>,
16    }
17
18    impl<E: Error + 'static> From<E> for Report {
19        fn from(error: E) -> Self {
20            Report { error: Arc::new(error) }
21        }
22    }
23
24    impl fmt::Display for Report {
25        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
26            let error = &self.error;
27
28            write!(f, "{error}")?;
29
30            if let Some(cause) = error.source() {
31                write!(f, "\n\nCaused by:")?;
32
33                let multiple = cause.source().is_some();
34
35                for (ind, error) in Source::new(cause).enumerate() {
36                    writeln!(f)?;
37                    let mut indented = Indented { inner: f };
38                    if multiple {
39                        write!(indented, "{ind: >4}: {error}")?;
40                    } else {
41                        write!(indented, "      {error}")?;
42                    }
43                }
44            }
45
46            Ok(())
47        }
48    }
49
50    impl fmt::Debug for Report {
51        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
52            fmt::Display::fmt(self, f)
53        }
54    }
55
56    #[derive(Clone, Debug)]
57    struct Source<'a> {
58        current: Option<&'a (dyn Error + 'static)>,
59    }
60
61    impl<'a> Source<'a> {
62        fn new(error: &'a (dyn Error + 'static)) -> Self {
63            Self { current: Some(error) }
64        }
65    }
66
67    impl<'a> Iterator for Source<'a> {
68        type Item = &'a (dyn Error + 'static);
69
70        fn next(&mut self) -> Option<Self::Item> {
71            let current = self.current;
72            self.current = self.current.and_then(Error::source);
73            current
74        }
75
76        fn size_hint(&self) -> (usize, Option<usize>) {
77            if self.current.is_some() { (1, None) } else { (0, Some(0)) }
78        }
79    }
80
81    impl std::iter::FusedIterator for Source<'_> {}
82
83    struct Indented<'a, D> {
84        inner: &'a mut D,
85    }
86
87    impl<T> Write for Indented<'_, T>
88    where
89        T: Write,
90    {
91        fn write_str(&mut self, s: &str) -> fmt::Result {
92            for (i, line) in s.split('\n').enumerate() {
93                if i > 0 {
94                    self.inner.write_char('\n')?;
95                    self.inner.write_str("      ")?;
96                }
97
98                self.inner.write_str(line)?;
99            }
100
101            Ok(())
102        }
103    }
104}