Skip to main content

fedimint_util_error/
lib.rs

1use std::fmt::Formatter;
2use std::{error, fmt};
3
4/// A wrapper with `fmt::Display` for any `E : Error` that will print chain
5/// of causes
6pub struct FmtErrorCompact<'e, E>(pub &'e E);
7
8impl<E> fmt::Display for FmtErrorCompact<'_, E>
9where
10    E: error::Error,
11{
12    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
13        let mut source_opt: Option<&dyn std::error::Error> = Some(self.0);
14
15        while source_opt.is_some() {
16            let source = source_opt.take().expect("Just checked");
17            f.write_fmt(format_args!("{source}"))?;
18
19            source_opt = source.source();
20            if source_opt.is_some() {
21                f.write_str(": ")?;
22            }
23        }
24        Ok(())
25    }
26}
27
28/// A wrapper with `fmt::Display` for [`anyhow::Error`] that will print
29/// chain of causes
30pub struct FmtCompactErrorAnyhow<'e>(pub &'e anyhow::Error);
31
32impl fmt::Display for FmtCompactErrorAnyhow<'_> {
33    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
34        // <https://docs.rs/anyhow/latest/anyhow/struct.Error.html#display-representations>
35        f.write_fmt(format_args!("{:#}", self.0))
36    }
37}
38
39/// Simple utility trait to print error chains
40pub trait FmtCompact<'a> {
41    type Report: fmt::Display + 'a;
42    fn fmt_compact(self) -> Self::Report;
43}
44
45/// Simple utility trait to print error chains (for [`anyhow::Error`])
46pub trait FmtCompactAnyhow<'a> {
47    type Report: fmt::Display + 'a;
48    fn fmt_compact_anyhow(self) -> Self::Report;
49}
50
51impl<'e, E> FmtCompact<'e> for &'e E
52where
53    E: error::Error,
54{
55    type Report = FmtErrorCompact<'e, E>;
56
57    fn fmt_compact(self) -> Self::Report {
58        FmtErrorCompact(self)
59    }
60}
61
62impl<'e> FmtCompactAnyhow<'e> for &'e anyhow::Error {
63    type Report = FmtCompactErrorAnyhow<'e>;
64
65    fn fmt_compact_anyhow(self) -> Self::Report {
66        FmtCompactErrorAnyhow(self)
67    }
68}
69
70/// A wrapper with `fmt::Display` for `Result<T, E>` where `E: Error` that
71/// prints the error chain on `Err` or `-` on `Ok`
72pub struct FmtCompactResultDisplay<'a, T, E>(pub &'a Result<T, E>);
73
74impl<T, E: error::Error> fmt::Display for FmtCompactResultDisplay<'_, T, E> {
75    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
76        match self.0 {
77            Ok(_) => f.write_str("-"),
78            Err(e) => FmtErrorCompact(e).fmt(f),
79        }
80    }
81}
82
83/// A wrapper with `fmt::Display` for `Result<T, anyhow::Error>` that
84/// prints the error chain on `Err` or `-` on `Ok`
85pub struct FmtCompactResultAnyhowDisplay<'a, T>(pub &'a Result<T, anyhow::Error>);
86
87impl<T> fmt::Display for FmtCompactResultAnyhowDisplay<'_, T> {
88    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
89        match self.0 {
90            Ok(_) => f.write_str("-"),
91            Err(e) => FmtCompactErrorAnyhow(e).fmt(f),
92        }
93    }
94}
95
96/// Extension trait to format `Result<T, E>` compactly (for `E: Error`)
97pub trait FmtCompactResult<'a> {
98    type Report: fmt::Display + 'a;
99    fn fmt_compact_result(&'a self) -> Self::Report;
100}
101
102/// Extension trait to format `Result<T, anyhow::Error>` compactly
103pub trait FmtCompactResultAnyhow<'a> {
104    type Report: fmt::Display + 'a;
105    fn fmt_compact_result_anyhow(&'a self) -> Self::Report;
106}
107
108impl<'a, T, E> FmtCompactResult<'a> for Result<T, E>
109where
110    E: error::Error + 'a,
111    T: 'a,
112{
113    type Report = FmtCompactResultDisplay<'a, T, E>;
114
115    fn fmt_compact_result(&'a self) -> Self::Report {
116        FmtCompactResultDisplay(self)
117    }
118}
119
120impl<'a, T: 'a> FmtCompactResultAnyhow<'a> for Result<T, anyhow::Error> {
121    type Report = FmtCompactResultAnyhowDisplay<'a, T>;
122
123    fn fmt_compact_result_anyhow(&'a self) -> Self::Report {
124        FmtCompactResultAnyhowDisplay(self)
125    }
126}
127
128#[cfg(test)]
129mod test;