timvw_rust_runtime/
error.rs1use std::error::Error as StdError;
2use std::fmt;
3
4use crate::BoxError;
5
6pub struct Error {
8 kind: Kind,
9 source: Option<BoxError>,
10}
11
12#[derive(Clone, Copy, Debug, PartialEq, Eq)]
13enum Kind {
14 Builder,
15 Request,
16 Body,
17 Decode,
18}
19
20impl Error {
21 pub(crate) fn builder(source: impl Into<BoxError>) -> Self {
22 Self {
23 kind: Kind::Builder,
24 source: Some(source.into()),
25 }
26 }
27
28 pub(crate) fn request(source: impl Into<BoxError>) -> Self {
29 Self {
30 kind: Kind::Request,
31 source: Some(source.into()),
32 }
33 }
34
35 pub(crate) fn body(source: impl Into<BoxError>) -> Self {
36 Self {
37 kind: Kind::Body,
38 source: Some(source.into()),
39 }
40 }
41
42 pub(crate) fn decode(source: impl Into<BoxError>) -> Self {
43 Self {
44 kind: Kind::Decode,
45 source: Some(source.into()),
46 }
47 }
48
49 pub fn is_builder(&self) -> bool {
51 self.kind == Kind::Builder
52 }
53
54 pub fn is_request(&self) -> bool {
57 self.kind == Kind::Request
58 }
59
60 pub fn is_body(&self) -> bool {
62 self.kind == Kind::Body
63 }
64
65 pub fn is_decode(&self) -> bool {
67 self.kind == Kind::Decode
68 }
69
70 pub fn is_timeout(&self) -> bool {
72 let mut source: Option<&(dyn StdError + 'static)> = self.source.as_deref().map(|e| e as _);
73 while let Some(error) = source {
74 if error.to_string() == "request timed out" {
75 return true;
76 }
77 #[cfg(feature = "reqwest")]
78 if let Some(error) = error.downcast_ref::<reqwest::Error>() {
79 if error.is_timeout() {
80 return true;
81 }
82 }
83 source = error.source();
84 }
85 false
86 }
87
88 pub fn is_connect(&self) -> bool {
90 #[cfg(feature = "reqwest")]
91 {
92 let mut source: Option<&(dyn StdError + 'static)> =
93 self.source.as_deref().map(|e| e as _);
94 while let Some(error) = source {
95 if let Some(error) = error.downcast_ref::<reqwest::Error>() {
96 if error.is_connect() {
97 return true;
98 }
99 }
100 source = error.source();
101 }
102 }
103 false
104 }
105}
106
107impl fmt::Debug for Error {
108 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
109 f.debug_struct("Error")
110 .field("kind", &self.kind)
111 .field("source", &self.source)
112 .finish()
113 }
114}
115
116impl fmt::Display for Error {
117 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
118 let what = match self.kind {
119 Kind::Builder => "error building the request",
120 Kind::Request => "error sending the request",
121 Kind::Body => "error reading the response body",
122 Kind::Decode => "error decoding the response body",
123 };
124 match &self.source {
125 Some(source) => write!(f, "{what}: {source}"),
126 None => f.write_str(what),
127 }
128 }
129}
130
131impl StdError for Error {
132 fn source(&self) -> Option<&(dyn StdError + 'static)> {
133 self.source.as_deref().map(|e| e as _)
134 }
135}