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