rust_ev_verifier_lib/
error_utils.rs1use std::fmt::Display;
2
3#[derive(Debug, Clone)]
7pub struct ErrorChain<'a, 'b> {
8 inner: Option<&'a (dyn std::error::Error + 'b)>,
9}
10
11impl<'a, 'b> ErrorChain<'a, 'b> {
12 pub fn new(error: &'a (dyn std::error::Error + 'b)) -> Self {
14 ErrorChain { inner: Some(error) }
15 }
16}
17
18impl<'a, 'b> Iterator for ErrorChain<'a, 'b> {
19 type Item = &'a (dyn std::error::Error + 'b);
20
21 fn next(&mut self) -> Option<Self::Item> {
22 match self.inner {
23 None => None,
24 Some(e) => {
25 self.inner = e.source();
26 Some(e)
27 }
28 }
29 }
30}
31
32#[derive(Debug, Clone)]
33pub struct Report<'a> {
34 inner: &'a dyn std::error::Error,
35}
36
37impl<'a> Report<'a> {
38 pub fn new(error: &'a dyn std::error::Error) -> Self {
39 Self { inner: error }
40 }
41}
42
43impl<'a> Display for Report<'a> {
44 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
45 let error_str = ErrorChain::new(self.inner)
46 .map(|e| e.to_string())
47 .collect::<Vec<_>>();
48 let mut res = vec![self.inner.to_string()];
49 if error_str.len() > 1 {
50 res.push("backtrace:".to_string());
51 res.append(
52 &mut error_str
53 .iter()
54 .enumerate()
55 .map(|(i, s)| format!("{i}: {s}"))
56 .collect(),
57 );
58 }
59 write!(f, "{}", res.join("\n"))
60 }
61}
62
63#[cfg(test)]
64mod test {
65 use super::*;
66 use thiserror::Error;
67
68 #[derive(Error, Debug)]
69 #[error("inner 21 error")]
70 struct Inner21 {}
71
72 #[derive(Error, Debug)]
73 #[error("inner 22 error")]
74 struct Inner22 {}
75
76 #[derive(Error, Debug)]
77 enum Inner {
78 #[error("Context 21")]
79 Inner21 { source: Inner21 },
80 #[error("Context 22")]
81 Inner22 { source: Inner22 },
82 }
83
84 #[derive(Error, Debug)]
85 enum Outer {
86 #[error("Context Inner")]
87 Inner { source: Inner },
88 }
89
90 #[test]
91 fn test_iter() {
92 let e = Outer::Inner {
93 source: Inner::Inner21 { source: Inner21 {} },
94 };
95 let res = ErrorChain::new(&e)
96 .map(|e| e.to_string())
97 .collect::<Vec<_>>();
98 assert_eq!(
99 res,
100 vec![
101 "Context Inner".to_string(),
102 "Context 21".to_string(),
103 "inner 21 error".to_string()
104 ]
105 )
106 }
107
108 #[test]
109 fn test_iter2() {
110 let e = Outer::Inner {
111 source: Inner::Inner22 { source: Inner22 {} },
112 };
113 let res = ErrorChain::new(&e)
114 .map(|e| e.to_string())
115 .collect::<Vec<_>>();
116 assert_eq!(
117 res,
118 vec![
119 "Context Inner".to_string(),
120 "Context 22".to_string(),
121 "inner 22 error".to_string()
122 ]
123 )
124 }
125}