fedimint_core/util/
error.rs1use std::fmt::Formatter;
2use std::{error, fmt};
3
4pub 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
28pub struct FmtCompactErrorAnyhow<'e>(pub &'e anyhow::Error);
31
32impl fmt::Display for FmtCompactErrorAnyhow<'_> {
33 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
34 f.write_fmt(format_args!("{:#}", self.0))
36 }
37}
38
39pub trait FmtCompact<'a> {
41 type Report: fmt::Display + 'a;
42 fn fmt_compact(self) -> Self::Report;
43}
44
45pub 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#[cfg(test)]
71mod test {
72 use std::io;
73
74 use anyhow::Context as _;
75
76 use super::*;
77
78 #[test]
79 pub(crate) fn fmt_compact_anyhow_sanity() {
80 fn foo() -> anyhow::Result<()> {
81 anyhow::bail!("Foo")
82 }
83
84 fn bar() -> anyhow::Result<()> {
85 foo().context("xyz")?;
86 unreachable!()
87 }
88
89 let Err(err) = bar() else {
90 panic!("abc");
91 };
92 assert_eq!(err.fmt_compact_anyhow().to_string(), "xyz: Foo");
93 }
94
95 #[test]
96 pub(crate) fn fmt_compact_sanity() {
97 fn foo() -> Result<(), io::Error> {
98 Err(io::Error::other("d"))
99 }
100
101 #[derive(Debug)]
102 struct BarError {
103 inner: io::Error,
104 }
105
106 impl std::error::Error for BarError {
107 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
108 Some(&self.inner)
109 }
110 }
111
112 impl fmt::Display for BarError {
113 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
114 f.write_str("BarError")
115 }
116 }
117
118 fn bar() -> Result<(), BarError> {
119 Err(BarError {
120 inner: foo().expect_err("wat"),
121 })?;
122 unreachable!()
123 }
124
125 let Err(err) = bar() else {
126 panic!("abc");
127 };
128 assert_eq!(err.fmt_compact().to_string(), "BarError: d");
129 }
130}