1use crate::codes::ErrorCode;
5
6pub trait ErrorStacks<C>
9where
10 C: Send + Sync + 'static + Eq + PartialEq + Clone,
11{
12 fn err_code(&self) -> Option<&C>;
14 fn with_err_code(self, code: C) -> Self;
16 fn with_no_err_code(self) -> Self;
18 fn err_uri(&self) -> Option<&str>;
20 fn with_err_uri(self, uri: String) -> Self;
22 fn with_no_err_uri(self) -> Self;
24 fn with_err_msg(self, error: impl std::fmt::Display + Send + Sync + 'static) -> Self;
26 fn with_no_err_msg(self) -> Self;
28 fn stack_err(self) -> Self;
30 fn stack_err_msg(self, error: impl std::fmt::Display + Send + Sync + 'static) -> Self;
32}
33
34impl<T, E, C> ErrorStacks<C> for Result<T, E>
36where
37 C: Send + Sync + 'static + Eq + PartialEq + Clone,
38 E: ErrorStacks<C>,
39{
40 fn err_code(&self) -> Option<&C> {
41 self.as_ref().err().and_then(|e| e.err_code())
42 }
43
44 fn with_err_code(self, code: C) -> Self {
45 self.map_err(|e| e.with_err_code(code))
46 }
47
48 fn with_no_err_code(self) -> Self {
49 self.map_err(|e| e.with_no_err_code())
50 }
51
52 fn err_uri(&self) -> Option<&str> {
53 self.as_ref().err().and_then(|e| e.err_uri())
54 }
55
56 fn with_err_uri(self, uri: String) -> Self {
57 self.map_err(|e| e.with_err_uri(uri))
58 }
59
60 fn with_no_err_uri(self) -> Self {
61 self.map_err(|e| e.with_no_err_uri())
62 }
63
64 fn with_err_msg(self, error: impl std::fmt::Display + Send + Sync + 'static) -> Self {
65 self.map_err(|e| e.with_err_msg(error))
66 }
67
68 fn with_no_err_msg(self) -> Self {
69 self.map_err(|e| e.with_no_err_msg())
70 }
71
72 fn stack_err(self) -> Self {
73 self.map_err(|e| e.stack_err())
74 }
75
76 fn stack_err_msg(self, error: impl std::fmt::Display + Send + Sync + 'static) -> Self {
77 self.map_err(|e| e.stack_err_msg(error))
78 }
79}
80
81#[derive(Default)]
83pub struct StackError {
84 message: Option<Box<dyn std::fmt::Display + Send + Sync + 'static>>,
85 source: Option<Box<StackError>>,
86 code: Option<ErrorCode>,
87 uri: Option<String>,
88}
89
90impl StackError {
91 pub fn new() -> Self {
93 Self::default()
94 }
95
96 pub fn from_msg(error: impl std::fmt::Display + Send + Sync + 'static) -> Self {
99 Self {
100 message: Some(Box::new(error)),
101 ..Default::default()
102 }
103 }
104}
105
106impl ErrorStacks<ErrorCode> for StackError {
107 fn err_code(&self) -> Option<&ErrorCode> {
108 self.code.as_ref()
109 }
110
111 fn with_err_code(self, code: ErrorCode) -> Self {
112 Self {
113 code: Some(code),
114 ..self
115 }
116 }
117
118 fn with_no_err_code(self) -> Self {
119 Self { code: None, ..self }
120 }
121
122 fn err_uri(&self) -> Option<&str> {
123 self.uri.as_deref()
124 }
125
126 fn with_err_uri(self, uri: String) -> Self {
127 Self {
128 uri: Some(uri),
129 ..self
130 }
131 }
132
133 fn with_no_err_uri(self) -> Self {
134 Self { uri: None, ..self }
135 }
136
137 fn with_err_msg(self, message: impl std::fmt::Display + Send + Sync + 'static) -> Self {
138 Self {
139 message: Some(Box::new(message)),
140 ..self
141 }
142 }
143
144 fn with_no_err_msg(self) -> Self {
145 Self {
146 message: None,
147 ..self
148 }
149 }
150
151 fn stack_err(self) -> Self {
152 let code = self.code;
153 let uri = self.uri.clone();
154 Self {
155 message: None,
156 source: Some(Box::new(self)),
157 code,
158 uri,
159 }
160 }
161
162 fn stack_err_msg(self, message: impl std::fmt::Display + Send + Sync + 'static) -> Self {
163 let code = self.code;
164 let uri = self.uri.clone();
165 Self {
166 message: Some(Box::new(message)),
167 source: Some(Box::new(self)),
168 code,
169 uri,
170 }
171 }
172}
173
174impl std::fmt::Display for StackError {
175 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
176 match &self.message {
177 Some(error) => {
178 write!(f, "{}", error)
179 }
180 None => Ok(()),
181 }
182 }
183}
184
185impl std::fmt::Debug for StackError {
186 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
187 for (idx, err) in std::iter::successors(Some(self), |e| e.source.as_deref())
188 .collect::<Vec<_>>()
189 .into_iter()
190 .rev()
191 .enumerate()
192 {
193 if idx > 0 {
194 writeln!(f)?;
195 }
196 write!(f, "{err}")?;
197 }
198 Ok(())
199 }
200}
201
202impl std::error::Error for StackError {
203 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
204 match &self.source {
205 Some(source) => Some(source.as_ref()),
206 None => None,
207 }
208 }
209}