1use std::any::Any;
16use std::fmt::{Debug, Formatter};
17use std::io::ErrorKind;
18use std::str::FromStr;
19use std::sync::Arc;
20
21use serde::{Deserialize, Deserializer, Serializer};
22use snafu::{FromString, Snafu};
23
24use crate::status_code::StatusCode;
25
26#[derive(Debug, Clone, Copy, PartialEq, Eq)]
32pub enum RetryHint {
33 Retryable,
35 NonRetryable,
39}
40
41const RETRY_HINT_RETRYABLE: &str = "retryable";
42const RETRY_HINT_NON_RETRYABLE: &str = "non_retryable";
43
44impl RetryHint {
45 pub fn is_retryable(self) -> bool {
46 matches!(self, RetryHint::Retryable)
47 }
48
49 pub fn as_str(self) -> &'static str {
50 match self {
51 RetryHint::Retryable => RETRY_HINT_RETRYABLE,
52 RetryHint::NonRetryable => RETRY_HINT_NON_RETRYABLE,
53 }
54 }
55
56 pub fn serialize_as_str<S>(hint: &Self, serializer: S) -> Result<S::Ok, S::Error>
57 where
58 S: Serializer,
59 {
60 serializer.serialize_str(hint.as_str())
61 }
62
63 pub fn deserialize_from_str<'de, D>(deserializer: D) -> Result<Self, D::Error>
64 where
65 D: Deserializer<'de>,
66 {
67 let hint = String::deserialize(deserializer)?;
68 hint.parse::<RetryHint>()
69 .map_err(|_| serde::de::Error::custom(format!("unknown retry hint: {hint}")))
70 }
71}
72
73impl FromStr for RetryHint {
74 type Err = ();
75
76 fn from_str(s: &str) -> Result<Self, Self::Err> {
77 match s {
78 RETRY_HINT_RETRYABLE => Ok(RetryHint::Retryable),
79 RETRY_HINT_NON_RETRYABLE => Ok(RetryHint::NonRetryable),
80 _ => Err(()),
81 }
82 }
83}
84
85pub fn retry_hint_from_io_error(error: &std::io::Error) -> RetryHint {
92 match error.kind() {
93 ErrorKind::ConnectionRefused
94 | ErrorKind::ConnectionReset
95 | ErrorKind::HostUnreachable
96 | ErrorKind::NetworkUnreachable
97 | ErrorKind::ConnectionAborted
98 | ErrorKind::NotConnected
99 | ErrorKind::NetworkDown
100 | ErrorKind::BrokenPipe
101 | ErrorKind::WouldBlock
102 | ErrorKind::StaleNetworkFileHandle
103 | ErrorKind::TimedOut
104 | ErrorKind::ResourceBusy
105 | ErrorKind::Interrupted => RetryHint::Retryable,
106
107 _ => RetryHint::NonRetryable,
108 }
109}
110
111pub trait ErrorExt: StackError {
113 fn status_code(&self) -> StatusCode {
115 StatusCode::Unknown
116 }
117
118 fn retry_hint(&self) -> RetryHint {
124 RetryHint::NonRetryable
125 }
126
127 fn is_retryable(&self) -> bool {
132 self.retry_hint().is_retryable()
133 }
134
135 fn as_any(&self) -> &dyn Any;
138
139 fn output_msg(&self) -> String
140 where
141 Self: Sized,
142 {
143 match self.status_code() {
144 StatusCode::Unknown | StatusCode::Internal => {
145 format!("Internal error: {}", self.status_code() as u32)
147 }
148 _ => {
149 let error = self.last();
150 if let Some(external_error) = error.source() {
151 let external_root = external_error.sources().last().unwrap();
152
153 if error.transparent() {
154 format!("{external_root}")
155 } else {
156 format!("{error}: {external_root}")
157 }
158 } else {
159 format!("{error}")
160 }
161 }
162 }
163 }
164
165 fn root_cause(&self) -> Option<&dyn std::error::Error>
167 where
168 Self: Sized,
169 {
170 let error = self.last();
171 if let Some(external_error) = error.source() {
172 let external_root = external_error.sources().last().unwrap();
173 Some(external_root)
174 } else {
175 None
176 }
177 }
178}
179
180pub trait StackError: std::error::Error {
181 fn debug_fmt(&self, layer: usize, buf: &mut Vec<String>);
182
183 fn next(&self) -> Option<&dyn StackError>;
184
185 fn last(&self) -> &dyn StackError
186 where
187 Self: Sized,
188 {
189 let Some(mut result) = self.next() else {
190 return self;
191 };
192 while let Some(err) = result.next() {
193 result = err;
194 }
195 result
196 }
197
198 fn transparent(&self) -> bool {
203 false
204 }
205}
206
207impl<T: ?Sized + StackError> StackError for Arc<T> {
208 fn debug_fmt(&self, layer: usize, buf: &mut Vec<String>) {
209 self.as_ref().debug_fmt(layer, buf)
210 }
211
212 fn next(&self) -> Option<&dyn StackError> {
213 self.as_ref().next()
214 }
215}
216
217impl<T: StackError> StackError for Box<T> {
218 fn debug_fmt(&self, layer: usize, buf: &mut Vec<String>) {
219 self.as_ref().debug_fmt(layer, buf)
220 }
221
222 fn next(&self) -> Option<&dyn StackError> {
223 self.as_ref().next()
224 }
225}
226
227pub type WhateverResult<T> = Result<T, Whatever>;
231
232#[derive(Snafu)]
233#[snafu(display("{inner}"))]
234pub struct Whatever {
235 inner: snafu::Whatever,
236}
237
238impl Debug for Whatever {
239 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
240 write!(f, "{}", self.inner)
241 }
242}
243
244impl<E: ErrorExt> From<E> for Whatever {
245 fn from(e: E) -> Self {
246 Self {
247 inner: FromString::without_source(format!("{e:?}")),
248 }
249 }
250}
251
252impl From<String> for Whatever {
253 fn from(s: String) -> Self {
254 Self {
255 inner: FromString::without_source(s),
256 }
257 }
258}
259
260pub struct BoxedError {
262 inner: Box<dyn crate::ext::ErrorExt + Send + Sync>,
263}
264
265impl BoxedError {
266 pub fn new<E: crate::ext::ErrorExt + Send + Sync + 'static>(err: E) -> Self {
267 Self {
268 inner: Box::new(err),
269 }
270 }
271
272 pub fn into_inner(self) -> Box<dyn crate::ext::ErrorExt + Send + Sync> {
273 self.inner
274 }
275}
276
277impl std::fmt::Debug for BoxedError {
278 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
279 let mut buf = vec![];
280 self.debug_fmt(0, &mut buf);
281 write!(f, "{}", buf.join("\n"))
282 }
283}
284
285impl std::fmt::Display for BoxedError {
286 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
287 write!(f, "{}", self.inner)
288 }
289}
290
291impl std::error::Error for BoxedError {
292 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
293 self.inner.source()
294 }
295}
296
297impl crate::ext::ErrorExt for BoxedError {
298 fn status_code(&self) -> crate::status_code::StatusCode {
299 self.inner.status_code()
300 }
301
302 fn retry_hint(&self) -> RetryHint {
303 self.inner.retry_hint()
304 }
305
306 fn as_any(&self) -> &dyn std::any::Any {
307 self.inner.as_any()
308 }
309}
310
311impl crate::snafu::ErrorCompat for BoxedError {
314 fn backtrace(&self) -> Option<&crate::snafu::Backtrace> {
315 None
316 }
317}
318
319impl StackError for BoxedError {
320 fn debug_fmt(&self, layer: usize, buf: &mut Vec<String>) {
321 self.inner.debug_fmt(layer, buf)
322 }
323
324 fn next(&self) -> Option<&dyn StackError> {
325 self.inner.next()
326 }
327}
328
329#[derive(Debug)]
331pub struct PlainError {
332 msg: String,
333 status_code: StatusCode,
334}
335
336impl PlainError {
337 pub fn new(msg: String, status_code: StatusCode) -> Self {
338 Self { msg, status_code }
339 }
340}
341
342impl std::fmt::Display for PlainError {
343 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
344 write!(f, "{}", self.msg)
345 }
346}
347
348impl std::error::Error for PlainError {
349 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
350 None
351 }
352}
353
354impl crate::ext::ErrorExt for PlainError {
355 fn status_code(&self) -> crate::status_code::StatusCode {
356 self.status_code
357 }
358
359 fn as_any(&self) -> &dyn std::any::Any {
360 self as _
361 }
362}
363
364impl StackError for PlainError {
365 fn debug_fmt(&self, layer: usize, buf: &mut Vec<String>) {
366 buf.push(format!("{}: {}", layer, self.msg))
367 }
368
369 fn next(&self) -> Option<&dyn StackError> {
370 None
371 }
372}