1use super::*;
2
3use core::fmt::{Debug, Display};
4use core::result::Result;
5use std::error::Error;
6use std::io;
7
8pub trait NetworkResultExt<T> {
12 fn into_network_result(self) -> NetworkResult<T>;
13}
14
15impl<T> NetworkResultExt<T> for Result<T, TimeoutError> {
16 fn into_network_result(self) -> NetworkResult<T> {
17 self.ok()
18 .map(|v| NetworkResult::<T>::Value(v))
19 .unwrap_or(NetworkResult::<T>::Timeout)
20 }
21}
22
23pub trait IoNetworkResultExt<T> {
24 fn into_network_result(self) -> io::Result<NetworkResult<T>>;
25}
26
27fn io_error_kind_from_error<T>(e: io::Error) -> io::Result<NetworkResult<T>> {
28 #[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
29 if let Some(os_err) = e.raw_os_error() {
30 if os_err == libc::EHOSTUNREACH || os_err == libc::ENETUNREACH {
31 return Ok(NetworkResult::NoConnection(e));
32 }
33 }
34 #[cfg(windows)]
35 if let Some(os_err) = e.raw_os_error() {
36 if os_err == winapi::um::winsock2::WSAENETRESET
37 || os_err == winapi::um::winsock2::WSAENETUNREACH
38 {
39 return Ok(NetworkResult::NoConnection(e));
40 }
41 }
42 match e.kind() {
43 io::ErrorKind::TimedOut => Ok(NetworkResult::Timeout),
44 io::ErrorKind::UnexpectedEof
45 | io::ErrorKind::NotConnected
46 | io::ErrorKind::BrokenPipe
47 | io::ErrorKind::ConnectionAborted
48 | io::ErrorKind::ConnectionRefused
49 | io::ErrorKind::ConnectionReset => Ok(NetworkResult::NoConnection(e)),
50 io::ErrorKind::InvalidInput | io::ErrorKind::InvalidData => {
51 Ok(NetworkResult::InvalidMessage(e.to_string()))
52 }
53 io::ErrorKind::AddrNotAvailable | io::ErrorKind::AddrInUse => {
54 Ok(NetworkResult::AlreadyExists(e))
55 }
56 _ => Err(e),
57 }
58}
59
60impl<T> IoNetworkResultExt<T> for io::Result<T> {
61 fn into_network_result(self) -> io::Result<NetworkResult<T>> {
62 match self {
63 Ok(v) => Ok(NetworkResult::Value(v)),
64 Err(e) => io_error_kind_from_error(e),
65 }
66 }
67}
68
69pub trait NetworkResultResultExt<T, E> {
70 fn into_result_network_result(self) -> Result<NetworkResult<T>, E>;
71}
72
73impl<T, E> NetworkResultResultExt<T, E> for NetworkResult<Result<T, E>> {
74 fn into_result_network_result(self) -> Result<NetworkResult<T>, E> {
75 match self {
76 NetworkResult::Timeout => Ok(NetworkResult::<T>::Timeout),
77 NetworkResult::ServiceUnavailable(s) => Ok(NetworkResult::<T>::ServiceUnavailable(s)),
78 NetworkResult::NoConnection(e) => Ok(NetworkResult::<T>::NoConnection(e)),
79 NetworkResult::AlreadyExists(e) => Ok(NetworkResult::<T>::AlreadyExists(e)),
80 NetworkResult::InvalidMessage(s) => Ok(NetworkResult::<T>::InvalidMessage(s)),
81 NetworkResult::Value(Ok(v)) => Ok(NetworkResult::<T>::Value(v)),
82 NetworkResult::Value(Err(e)) => Err(e),
83 }
84 }
85}
86
87pub trait FoldedNetworkResultExt<T> {
88 fn folded(self) -> io::Result<NetworkResult<T>>;
89}
90
91impl<T> FoldedNetworkResultExt<T> for io::Result<TimeoutOr<T>> {
92 fn folded(self) -> io::Result<NetworkResult<T>> {
93 match self {
94 Ok(TimeoutOr::Timeout) => Ok(NetworkResult::Timeout),
95 Ok(TimeoutOr::Value(v)) => Ok(NetworkResult::Value(v)),
96 Err(e) => io_error_kind_from_error(e),
97 }
98 }
99}
100
101impl<T> FoldedNetworkResultExt<T> for io::Result<NetworkResult<T>> {
102 fn folded(self) -> io::Result<NetworkResult<T>> {
103 match self {
104 Ok(v) => Ok(v),
105 Err(e) => io_error_kind_from_error(e),
106 }
107 }
108}
109
110#[must_use]
114pub enum NetworkResult<T> {
115 Timeout,
116 ServiceUnavailable(String),
117 NoConnection(io::Error),
118 AlreadyExists(io::Error),
119 InvalidMessage(String),
120 Value(T),
121}
122
123impl<T> NetworkResult<T> {
124 pub fn timeout() -> Self {
125 Self::Timeout
126 }
127 pub fn service_unavailable<S: ToString>(s: S) -> Self {
128 Self::ServiceUnavailable(s.to_string())
129 }
130 pub fn no_connection(e: io::Error) -> Self {
131 Self::NoConnection(e)
132 }
133 pub fn no_connection_other<S: ToString>(s: S) -> Self {
134 Self::NoConnection(io::Error::new(io::ErrorKind::Other, s.to_string()))
135 }
136 pub fn invalid_message<S: ToString>(s: S) -> Self {
137 Self::InvalidMessage(s.to_string())
138 }
139 pub fn already_exists(e: io::Error) -> Self {
140 Self::AlreadyExists(e)
141 }
142 pub fn value(value: T) -> Self {
143 Self::Value(value)
144 }
145
146 pub fn is_timeout(&self) -> bool {
147 matches!(self, Self::Timeout)
148 }
149 pub fn is_no_connection(&self) -> bool {
150 matches!(self, Self::NoConnection(_))
151 }
152 pub fn is_already_exists(&self) -> bool {
153 matches!(self, Self::AlreadyExists(_))
154 }
155 pub fn is_invalid_message(&self) -> bool {
156 matches!(self, Self::InvalidMessage(_))
157 }
158 pub fn is_value(&self) -> bool {
159 matches!(self, Self::Value(_))
160 }
161 pub fn map<X, F: Fn(T) -> X>(self, f: F) -> NetworkResult<X> {
162 match self {
163 Self::Timeout => NetworkResult::<X>::Timeout,
164 Self::ServiceUnavailable(s) => NetworkResult::<X>::ServiceUnavailable(s),
165 Self::NoConnection(e) => NetworkResult::<X>::NoConnection(e),
166 Self::AlreadyExists(e) => NetworkResult::<X>::AlreadyExists(e),
167 Self::InvalidMessage(s) => NetworkResult::<X>::InvalidMessage(s),
168 Self::Value(v) => NetworkResult::<X>::Value(f(v)),
169 }
170 }
171 pub fn into_io_result(self) -> Result<T, io::Error> {
172 match self {
173 Self::Timeout => Err(io::Error::new(io::ErrorKind::TimedOut, "Timed out")),
174 Self::ServiceUnavailable(s) => Err(io::Error::new(
175 io::ErrorKind::NotFound,
176 format!("Service unavailable: {}", s),
177 )),
178 Self::NoConnection(e) => Err(e),
179 Self::AlreadyExists(e) => Err(e),
180 Self::InvalidMessage(s) => Err(io::Error::new(
181 io::ErrorKind::InvalidData,
182 format!("Invalid message: {}", s),
183 )),
184 Self::Value(v) => Ok(v),
185 }
186 }
187}
188
189impl<T> From<NetworkResult<T>> for Option<T> {
190 fn from(t: NetworkResult<T>) -> Self {
191 match t {
192 NetworkResult::Value(v) => Some(v),
193 _ => None,
194 }
195 }
196}
197
198impl<T: Debug> Debug for NetworkResult<T> {
199 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
200 match self {
201 Self::Timeout => write!(f, "Timeout"),
202 Self::ServiceUnavailable(s) => f.debug_tuple("ServiceUnavailable").field(s).finish(),
203 Self::NoConnection(e) => f.debug_tuple("NoConnection").field(e).finish(),
204 Self::AlreadyExists(e) => f.debug_tuple("AlreadyExists").field(e).finish(),
205 Self::InvalidMessage(s) => f.debug_tuple("InvalidMessage").field(s).finish(),
206 Self::Value(v) => f.debug_tuple("Value").field(v).finish(),
207 }
208 }
209}
210
211impl<T> Display for NetworkResult<T> {
212 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
213 match self {
214 Self::Timeout => write!(f, "Timeout"),
215 Self::ServiceUnavailable(s) => write!(f, "ServiceUnavailable({})", s),
216 Self::NoConnection(e) => write!(f, "NoConnection({})", e.kind()),
217 Self::AlreadyExists(e) => write!(f, "AlreadyExists({})", e.kind()),
218 Self::InvalidMessage(s) => write!(f, "InvalidMessage({})", s),
219 Self::Value(_) => write!(f, "Value"),
220 }
221 }
222}
223
224impl<T: Debug + Display> Error for NetworkResult<T> {}
225
226#[macro_export]
230macro_rules! network_result_raise {
231 ($r: expr) => {
232 match $r {
233 NetworkResult::Timeout => return Ok(NetworkResult::Timeout),
234 NetworkResult::ServiceUnavailable(s) => return Ok(NetworkResult::ServiceUnavailable(s)),
235 NetworkResult::NoConnection(e) => return Ok(NetworkResult::NoConnection(e)),
236 NetworkResult::AlreadyExists(e) => return Ok(NetworkResult::AlreadyExists(e)),
237 NetworkResult::InvalidMessage(s) => return Ok(NetworkResult::InvalidMessage(s)),
238 NetworkResult::Value(_) => panic!("Can not raise value"),
239 }
240 };
241}
242
243#[macro_export]
244macro_rules! network_result_try {
245 ($r: expr) => {
246 match $r {
247 NetworkResult::Timeout => return Ok(NetworkResult::Timeout),
248 NetworkResult::ServiceUnavailable(s) => return Ok(NetworkResult::ServiceUnavailable(s)),
249 NetworkResult::NoConnection(e) => return Ok(NetworkResult::NoConnection(e)),
250 NetworkResult::AlreadyExists(e) => return Ok(NetworkResult::AlreadyExists(e)),
251 NetworkResult::InvalidMessage(s) => return Ok(NetworkResult::InvalidMessage(s)),
252 NetworkResult::Value(v) => v,
253 }
254 };
255 ($r:expr => $f:tt) => {
256 match $r {
257 NetworkResult::Timeout => {
258 $f;
259 return Ok(NetworkResult::Timeout);
260 }
261 NetworkResult::ServiceUnavailable(s) => {
262 $f;
263 return Ok(NetworkResult::ServiceUnavailable(s));
264 }
265 NetworkResult::NoConnection(e) => {
266 $f;
267 return Ok(NetworkResult::NoConnection(e));
268 }
269 NetworkResult::AlreadyExists(e) => {
270 $f;
271 return Ok(NetworkResult::AlreadyExists(e));
272 }
273 NetworkResult::InvalidMessage(s) => {
274 $f;
275 return Ok(NetworkResult::InvalidMessage(s));
276 }
277 NetworkResult::Value(v) => v,
278 }
279 };
280}
281
282#[macro_export]
283macro_rules! network_result_value_or_log {
284 ($self:ident $r:expr => $f:expr) => {
285 network_result_value_or_log!($self $r => [ "" ] $f )
286 };
287 ($self:ident $r:expr => [ $d:expr ] $f:expr) => { {
288 let __extra_message = if debug_target_enabled!("network_result") {
289 $d.to_string()
290 } else {
291 "".to_string()
292 };
293 match $r {
294 NetworkResult::Timeout => {
295 veilid_log!($self debug
296 "{} at {}@{}:{} in {}{}",
297 "Timeout",
298 file!(),
299 line!(),
300 column!(),
301 fn_name::uninstantiated!(),
302 __extra_message
303 );
304 $f
305 }
306 NetworkResult::ServiceUnavailable(ref s) => {
307 veilid_log!($self debug
308 "{}({}) at {}@{}:{} in {}{}",
309 "ServiceUnavailable",
310 s,
311 file!(),
312 line!(),
313 column!(),
314 fn_name::uninstantiated!(),
315 __extra_message
316 );
317 $f
318 }
319 NetworkResult::NoConnection(ref e) => {
320 veilid_log!($self debug
321 "{}({}) at {}@{}:{} in {}{}",
322 "No connection",
323 e.to_string(),
324 file!(),
325 line!(),
326 column!(),
327 fn_name::uninstantiated!(),
328 __extra_message
329 );
330 $f
331 }
332 NetworkResult::AlreadyExists(ref e) => {
333 veilid_log!($self debug
334 "{}({}) at {}@{}:{} in {}{}",
335 "Already exists",
336 e.to_string(),
337 file!(),
338 line!(),
339 column!(),
340 fn_name::uninstantiated!(),
341 __extra_message
342 );
343 $f
344 }
345 NetworkResult::InvalidMessage(ref s) => {
346 veilid_log!($self debug
347 "{}({}) at {}@{}:{} in {}{}",
348 "Invalid message",
349 s,
350 file!(),
351 line!(),
352 column!(),
353 fn_name::uninstantiated!(),
354 __extra_message
355 );
356 $f
357 }
358 NetworkResult::Value(v) => v,
359 }
360 } };
361
362}