1use std::{collections::VecDeque, fmt::Display};
2
3use derive_setters::Setters;
4use thiserror::Error;
5
6#[derive(Clone, PartialEq, Debug, Setters, Error)]
7pub struct Cause<E, T> {
8 pub error: E,
9 #[setters(skip)]
10 pub trace: VecDeque<T>,
11}
12
13impl<E: Display, T: Display> Display for Cause<E, T> {
14 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
15 write!(f, "[")?;
16 for (i, entry) in self.trace.iter().enumerate() {
17 if i > 0 {
18 write!(f, ", ")?;
19 }
20 write!(f, "{}", entry)?;
21 }
22 write!(f, "] {}", self.error)?;
23 Ok(())
24 }
25}
26
27impl<E, T> Cause<E, T> {
28 pub fn new(e: E) -> Self {
29 Cause {
30 error: e,
31 trace: Default::default(),
32 }
33 }
34
35 pub fn trace(mut self, t: T) -> Self {
36 self.trace.push_front(t);
37 self
38 }
39
40 pub fn transform<E1>(self, e: impl Fn(E) -> E1) -> Cause<E1, T> {
41 Cause {
42 error: e(self.error),
43 trace: self.trace,
44 }
45 }
46}
47
48#[cfg(test)]
49mod tests {
50 use pretty_assertions::assert_eq;
51
52 #[test]
53 fn test_display() {
54 use super::Cause;
55 let cause = Cause::new("error").trace("trace0").trace("trace1");
56 assert_eq!(cause.to_string(), "[trace1, trace0] error");
57 }
58}