Skip to main content

g_err/
gerr_source.rs

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
15/// Dyn-compatible trait for source's error id.
16pub trait IdSource: Any + Debug + Display + Send + Sync {}
17
18impl<T> IdSource for T where T: Any + Debug + Display + Send + Sync {}
19
20/// Dyn-compatible trait for source's error data.
21pub trait DataSource: Any + Debug + Send + Sync {}
22
23impl<T> DataSource for T where T: Any + Debug + Send + Sync {}
24
25/// GErrSource - GErr as source of error.
26pub struct GErrSource {
27    /// Error id, must implement Debug and Display.
28    pub id: Option<Box<dyn IdSource>>,
29
30    /// Error id as json value, support for numeric and string only.
31    ///
32    /// Passing other than numeric and string, will be ignored at serde.
33    #[cfg(feature = "serde")]
34    pub id_json: Option<serde_json::Value>,
35
36    /// Error code.
37    pub code: Option<Cow<'static, str>>,
38
39    /// Error message.
40    pub message: Cow<'static, str>,
41
42    /// Error sources.
43    pub sources: Option<Vec<Source>>,
44
45    /// Error tags.
46    pub tags: Option<Vec<Cow<'static, str>>>,
47
48    /// Error data.
49    pub data: Option<Box<dyn DataSource>>,
50
51    /// Error help.
52    pub help: Option<Cow<'static, str>>,
53
54    /// Error data as json values. Supports all json values.
55    #[cfg(feature = "serde")]
56    pub data_json: Option<serde_json::Value>,
57
58    /// Error location.
59    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}