1use std::any::Any;
16use std::sync::Arc;
17
18use crate::status_code::StatusCode;
19
20pub trait ErrorExt: StackError {
22 fn status_code(&self) -> StatusCode {
24 StatusCode::Unknown
25 }
26
27 fn as_any(&self) -> &dyn Any;
30
31 fn output_msg(&self) -> String
32 where
33 Self: Sized,
34 {
35 match self.status_code() {
36 StatusCode::Unknown | StatusCode::Internal => {
37 format!("Internal error: {}", self.status_code() as u32)
39 }
40 _ => {
41 let error = self.last();
42 if let Some(external_error) = error.source() {
43 let external_root = external_error.sources().last().unwrap();
44
45 if error.transparent() {
46 format!("{external_root}")
47 } else {
48 format!("{error}: {external_root}")
49 }
50 } else {
51 format!("{error}")
52 }
53 }
54 }
55 }
56
57 fn root_cause(&self) -> Option<&dyn std::error::Error>
59 where
60 Self: Sized,
61 {
62 let error = self.last();
63 if let Some(external_error) = error.source() {
64 let external_root = external_error.sources().last().unwrap();
65 Some(external_root)
66 } else {
67 None
68 }
69 }
70}
71
72pub trait StackError: std::error::Error {
73 fn debug_fmt(&self, layer: usize, buf: &mut Vec<String>);
74
75 fn next(&self) -> Option<&dyn StackError>;
76
77 fn last(&self) -> &dyn StackError
78 where
79 Self: Sized,
80 {
81 let Some(mut result) = self.next() else {
82 return self;
83 };
84 while let Some(err) = result.next() {
85 result = err;
86 }
87 result
88 }
89
90 fn transparent(&self) -> bool {
95 false
96 }
97}
98
99impl<T: ?Sized + StackError> StackError for Arc<T> {
100 fn debug_fmt(&self, layer: usize, buf: &mut Vec<String>) {
101 self.as_ref().debug_fmt(layer, buf)
102 }
103
104 fn next(&self) -> Option<&dyn StackError> {
105 self.as_ref().next()
106 }
107}
108
109impl<T: StackError> StackError for Box<T> {
110 fn debug_fmt(&self, layer: usize, buf: &mut Vec<String>) {
111 self.as_ref().debug_fmt(layer, buf)
112 }
113
114 fn next(&self) -> Option<&dyn StackError> {
115 self.as_ref().next()
116 }
117}
118
119pub struct BoxedError {
121 inner: Box<dyn crate::ext::ErrorExt + Send + Sync>,
122}
123
124impl BoxedError {
125 pub fn new<E: crate::ext::ErrorExt + Send + Sync + 'static>(err: E) -> Self {
126 Self {
127 inner: Box::new(err),
128 }
129 }
130
131 pub fn into_inner(self) -> Box<dyn crate::ext::ErrorExt + Send + Sync> {
132 self.inner
133 }
134}
135
136impl std::fmt::Debug for BoxedError {
137 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
138 let mut buf = vec![];
139 self.debug_fmt(0, &mut buf);
140 write!(f, "{}", buf.join("\n"))
141 }
142}
143
144impl std::fmt::Display for BoxedError {
145 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
146 write!(f, "{}", self.inner)
147 }
148}
149
150impl std::error::Error for BoxedError {
151 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
152 self.inner.source()
153 }
154}
155
156impl crate::ext::ErrorExt for BoxedError {
157 fn status_code(&self) -> crate::status_code::StatusCode {
158 self.inner.status_code()
159 }
160
161 fn as_any(&self) -> &dyn std::any::Any {
162 self.inner.as_any()
163 }
164}
165
166impl crate::snafu::ErrorCompat for BoxedError {
169 fn backtrace(&self) -> Option<&crate::snafu::Backtrace> {
170 None
171 }
172}
173
174impl StackError for BoxedError {
175 fn debug_fmt(&self, layer: usize, buf: &mut Vec<String>) {
176 self.inner.debug_fmt(layer, buf)
177 }
178
179 fn next(&self) -> Option<&dyn StackError> {
180 self.inner.next()
181 }
182}
183
184#[derive(Debug)]
186pub struct PlainError {
187 msg: String,
188 status_code: StatusCode,
189}
190
191impl PlainError {
192 pub fn new(msg: String, status_code: StatusCode) -> Self {
193 Self { msg, status_code }
194 }
195}
196
197impl std::fmt::Display for PlainError {
198 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
199 write!(f, "{}", self.msg)
200 }
201}
202
203impl std::error::Error for PlainError {
204 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
205 None
206 }
207}
208
209impl crate::ext::ErrorExt for PlainError {
210 fn status_code(&self) -> crate::status_code::StatusCode {
211 self.status_code
212 }
213
214 fn as_any(&self) -> &dyn std::any::Any {
215 self as _
216 }
217}
218
219impl StackError for PlainError {
220 fn debug_fmt(&self, layer: usize, buf: &mut Vec<String>) {
221 buf.push(format!("{}: {}", layer, self.msg))
222 }
223
224 fn next(&self) -> Option<&dyn StackError> {
225 None
226 }
227}