1pub mod clap;
2pub mod cors;
3pub mod crypto;
4#[cfg(feature = "testing")]
5pub mod fee;
6pub mod formatting;
7pub mod fs;
8pub mod grpc;
9pub mod limiter;
10pub mod logging;
11pub mod lru_cache;
12pub mod panic;
13pub mod signer;
14pub mod tracing;
15
16pub trait ErrorReport: std::error::Error {
17 fn as_report(&self) -> String {
19 use std::fmt::Write;
20 let mut report = self.to_string();
21
22 std::iter::successors(self.source(), |child| child.source())
24 .for_each(|source| write!(report, "\ncaused by: {source}").unwrap());
25
26 report
27 }
28
29 fn as_report_context(&self, context: &'static str) -> String {
32 format!("{context}: \ncaused by: {}", self.as_report())
33 }
34}
35
36impl<T: std::error::Error> ErrorReport for T {}
37
38pub trait FlattenResult<V, OuterError, InnerError>
42where
43 InnerError: Into<OuterError>,
44{
45 fn flatten_result(self) -> Result<V, OuterError>;
46}
47
48impl<V, OuterError, InnerError> FlattenResult<V, OuterError, InnerError>
49 for Result<Result<V, InnerError>, OuterError>
50where
51 OuterError: From<InnerError>,
52{
53 fn flatten_result(self) -> Result<V, OuterError> {
54 match self {
55 Ok(Ok(value)) => Ok(value),
56 Ok(Err(inner)) => Err(inner.into()),
57 Err(outer) => Err(outer),
58 }
59 }
60}
61
62#[cfg(test)]
63mod tests {
64 use crate::ErrorReport;
65
66 #[derive(thiserror::Error, Debug, Clone, PartialEq, Eq)]
67 pub enum TestSourceError {
68 #[error("source error")]
69 Source,
70 }
71
72 #[derive(thiserror::Error, Debug)]
73 pub enum TestError {
74 #[error("parent error")]
75 Parent(#[from] TestSourceError),
76 }
77
78 #[test]
79 fn as_report() {
80 let error = TestError::Parent(TestSourceError::Source);
81 assert_eq!("parent error\ncaused by: source error", error.as_report());
82 }
83
84 #[test]
85 fn as_report_context() {
86 let error = TestError::Parent(TestSourceError::Source);
87 assert_eq!(
88 "final error: \ncaused by: parent error\ncaused by: source error",
89 error.as_report_context("final error")
90 );
91 }
92}