1use std::collections::HashMap;
2
3use http::StatusCode;
4
5#[allow(unused_imports)]
7#[macro_use]
8extern crate error_info_macros;
9#[doc(hidden)]
10pub use error_info_macros::*;
11
12pub trait ErrorInfo {
14 fn status(&self) -> StatusCode;
16 fn code(&self) -> &'static str;
18 fn raw_message(&self) -> &'static str;
20 fn fields(&self) -> HashMap<String, String>;
22 fn message(&self) -> String {
24 let mut message = self.raw_message().to_string();
25 for (k, v) in self.fields() {
26 message = message.replace(&format!("{{{k}}}"), &v);
27 }
28 message
29 }
30}
31
32#[cfg(feature = "summary")]
33#[derive(Debug, serde::Serialize)]
34pub struct ErrorInfoSummary {
36 #[serde(serialize_with = "serialize_status")]
38 pub status: StatusCode,
39 pub code: &'static str,
41 pub raw_message: &'static str,
45}
46
47#[cfg(feature = "summary")]
48#[linkme::distributed_slice]
50pub static ERROR_INFO_SUMMARY: [fn() -> Vec<ErrorInfoSummary>] = [..];
51
52#[cfg(feature = "summary")]
53pub fn summary() -> Vec<ErrorInfoSummary> {
57 let mut ret = Vec::with_capacity(ERROR_INFO_SUMMARY.len());
58 for summaries_fn in ERROR_INFO_SUMMARY {
59 let mut summaries = summaries_fn();
60 ret.append(&mut summaries);
61 }
62 ret.sort_by_key(|s| (s.status, s.code));
63 ret
64}
65
66#[cfg(feature = "summary")]
67fn serialize_status<S>(status: &StatusCode, serializer: S) -> Result<S::Ok, S::Error>
68where
69 S: serde::Serializer,
70{
71 serializer.serialize_u16(status.as_u16())
72}