1extern crate alloc;
2
3use alloc::borrow::Cow;
4use alloc::boxed::Box;
5use alloc::vec::Vec;
6
7use core::{
8 any::Any,
9 error::Error,
10 fmt::{Debug, Display},
11};
12
13use crate::gerr::{ErrorLocation, Source};
14
15pub trait IdSource: Any + Debug + Display + Send + Sync {}
17
18impl<T> IdSource for T where T: Any + Debug + Display + Send + Sync {}
19
20pub trait DataSource: Any + Debug + Send + Sync {}
22
23impl<T> DataSource for T where T: Any + Debug + Send + Sync {}
24
25pub struct GErrSource {
27 pub id: Option<Box<dyn IdSource>>,
29
30 #[cfg(feature = "serde")]
34 pub id_json: Option<serde_json::Value>,
35
36 pub code: Option<Cow<'static, str>>,
38
39 pub message: Cow<'static, str>,
41
42 pub sources: Option<Vec<Source>>,
44
45 pub tags: Option<Vec<Cow<'static, str>>>,
47
48 pub data: Option<Box<dyn DataSource>>,
50
51 pub help: Option<Cow<'static, str>>,
53
54 #[cfg(feature = "serde")]
56 pub data_json: Option<serde_json::Value>,
57
58 pub location: Option<ErrorLocation>,
60}
61
62impl Debug for GErrSource {
63 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
64 let mut debug = f.debug_struct("GErrSource");
65
66 debug.field("id", &self.id);
67
68 #[cfg(feature = "serde")]
69 debug.field("id_json", &self.id_json);
70
71 debug
72 .field("code", &self.code)
73 .field("message", &self.message)
74 .field("sources", &self.sources)
75 .field("tags", &self.tags)
76 .field("data", &self.data);
77
78 #[cfg(feature = "serde")]
79 debug.field("data_json", &self.data_json);
80
81 debug
82 .field("help", &self.help)
83 .field("location", &self.location);
84
85 debug.finish()
86 }
87}
88
89impl Display for GErrSource {
90 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
91 if let Some(code) = self.code.as_deref() {
92 write!(f, "{code} - {}", self.message)
93 } else {
94 write!(f, "{}", self.message)
95 }
96 }
97}
98
99impl Error for GErrSource {
100 fn source(&self) -> Option<&(dyn Error + 'static)> {
101 if let Some(ref sources) = self.sources
102 && !sources.is_empty()
103 {
104 return sources.first().map(|s| match s {
105 Source::Err(e) => &**e as &(dyn Error + 'static),
106 Source::GErr(e) => &**e as &(dyn Error + 'static),
107 });
108 }
109 None
110 }
111}