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 Io,
19}
20
21impl Error {
22 pub(crate) fn builder(source: impl Into<BoxError>) -> Self {
23 Self {
24 kind: Kind::Builder,
25 source: Some(source.into()),
26 }
27 }
28
29 pub(crate) fn request(source: impl Into<BoxError>) -> Self {
30 Self {
31 kind: Kind::Request,
32 source: Some(source.into()),
33 }
34 }
35
36 pub(crate) fn body(source: impl Into<BoxError>) -> Self {
37 Self {
38 kind: Kind::Body,
39 source: Some(source.into()),
40 }
41 }
42
43 pub(crate) fn decode(source: impl Into<BoxError>) -> Self {
44 Self {
45 kind: Kind::Decode,
46 source: Some(source.into()),
47 }
48 }
49
50 pub(crate) fn io(source: impl Into<BoxError>) -> Self {
51 Self {
52 kind: Kind::Io,
53 source: Some(source.into()),
54 }
55 }
56
57 pub fn is_builder(&self) -> bool {
59 self.kind == Kind::Builder
60 }
61
62 pub fn is_request(&self) -> bool {
65 self.kind == Kind::Request
66 }
67
68 pub fn is_body(&self) -> bool {
70 self.kind == Kind::Body
71 }
72
73 pub fn is_decode(&self) -> bool {
75 self.kind == Kind::Decode
76 }
77
78 #[cfg_attr(
80 all(feature = "fs", not(target_family = "wasm")),
81 doc = "[`Response::save_to`](crate::Response::save_to) failing to write."
82 )]
83 #[cfg_attr(
84 not(all(feature = "fs", not(target_family = "wasm"))),
85 doc = "`Response::save_to` (feature `fs`, not on WebAssembly) failing to write."
86 )]
87 pub fn is_io(&self) -> bool {
89 self.kind == Kind::Io
90 }
91
92 #[cfg_attr(
94 feature = "time",
95 doc = "[`TimeoutLayer`](crate::timeout::TimeoutLayer), or an [`idle_timeout`](crate::sse::Events::idle_timeout)"
96 )]
97 #[cfg_attr(
98 not(feature = "time"),
99 doc = "`timeout::TimeoutLayer`, or an `idle_timeout` (both feature `time`)"
100 )]
101 pub fn is_timeout(&self) -> bool {
103 self.source
104 .as_deref()
105 .is_some_and(|source| is_timeout(source as _))
106 }
107
108 pub fn is_connect(&self) -> bool {
111 #[cfg(all(feature = "reqwest", not(target_family = "wasm")))]
112 {
113 let mut source: Option<&(dyn StdError + 'static)> =
114 self.source.as_deref().map(|e| e as _);
115 while let Some(error) = source {
116 if let Some(error) = error.downcast_ref::<reqwest::Error>() {
117 if error.is_connect() {
118 return true;
119 }
120 }
121 source = error.source();
122 }
123 }
124 false
125 }
126}
127
128impl fmt::Debug for Error {
129 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
130 f.debug_struct("Error")
131 .field("kind", &self.kind)
132 .field("source", &self.source)
133 .finish()
134 }
135}
136
137impl fmt::Display for Error {
138 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
139 let what = match self.kind {
140 Kind::Builder => "error building the request",
141 Kind::Request => "error sending the request",
142 Kind::Body => "error reading the response body",
143 Kind::Decode => "error decoding the response body",
144 Kind::Io => "I/O error",
145 };
146 match &self.source {
147 Some(source) => write!(f, "{what}: {source}"),
148 None => f.write_str(what),
149 }
150 }
151}
152
153impl StdError for Error {
154 fn source(&self) -> Option<&(dyn StdError + 'static)> {
155 self.source.as_deref().map(|e| e as _)
156 }
157}
158
159pub(crate) fn is_timeout(error: &(dyn StdError + 'static)) -> bool {
161 let mut source = Some(error);
162 while let Some(error) = source {
163 if error.to_string() == "request timed out" || error.is::<TimedOut>() {
164 return true;
165 }
166 #[cfg(feature = "reqwest")]
167 if let Some(error) = error.downcast_ref::<reqwest::Error>() {
168 if error.is_timeout() {
169 return true;
170 }
171 }
172 source = error.source();
173 }
174 false
175}
176
177#[derive(Debug)]
179#[cfg_attr(not(feature = "time"), allow(dead_code))]
180pub(crate) struct TimedOut(pub(crate) String);
181
182impl fmt::Display for TimedOut {
183 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
184 f.write_str(&self.0)
185 }
186}
187
188impl StdError for TimedOut {}