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
50 | io::ErrorKind::InvalidInput => Ok(NetworkResult::NoConnection(e)),
51 io::ErrorKind::InvalidData => Ok(NetworkResult::InvalidMessage(e.to_string())),
52 io::ErrorKind::AddrNotAvailable | io::ErrorKind::AddrInUse => {
53 Ok(NetworkResult::AlreadyExists(e))
54 }
55 _ => Err(e),
56 }
57}
58
59impl<T> IoNetworkResultExt<T> for io::Result<T> {
60 fn into_network_result(self) -> io::Result<NetworkResult<T>> {
61 match self {
62 Ok(v) => Ok(NetworkResult::Value(v)),
63 Err(e) => io_error_kind_from_error(e),
64 }
65 }
66}
67
68pub trait NetworkResultResultExt<T, E> {
69 fn into_result_network_result(self) -> Result<NetworkResult<T>, E>;
70}
71
72impl<T, E> NetworkResultResultExt<T, E> for NetworkResult<Result<T, E>> {
73 fn into_result_network_result(self) -> Result<NetworkResult<T>, E> {
74 match self {
75 NetworkResult::Timeout => Ok(NetworkResult::<T>::Timeout),
76 NetworkResult::ServiceUnavailable(s) => Ok(NetworkResult::<T>::ServiceUnavailable(s)),
77 NetworkResult::NoConnection(e) => Ok(NetworkResult::<T>::NoConnection(e)),
78 NetworkResult::AlreadyExists(e) => Ok(NetworkResult::<T>::AlreadyExists(e)),
79 NetworkResult::InvalidMessage(s) => Ok(NetworkResult::<T>::InvalidMessage(s)),
80 NetworkResult::Value(Ok(v)) => Ok(NetworkResult::<T>::Value(v)),
81 NetworkResult::Value(Err(e)) => Err(e),
82 }
83 }
84}
85
86pub trait FoldedNetworkResultExt<T> {
87 fn folded(self) -> io::Result<NetworkResult<T>>;
88}
89
90impl<T> FoldedNetworkResultExt<T> for io::Result<TimeoutOr<T>> {
91 fn folded(self) -> io::Result<NetworkResult<T>> {
92 match self {
93 Ok(TimeoutOr::Timeout) => Ok(NetworkResult::Timeout),
94 Ok(TimeoutOr::Value(v)) => Ok(NetworkResult::Value(v)),
95 Err(e) => io_error_kind_from_error(e),
96 }
97 }
98}
99
100impl<T> FoldedNetworkResultExt<T> for io::Result<NetworkResult<T>> {
101 fn folded(self) -> io::Result<NetworkResult<T>> {
102 match self {
103 Ok(v) => Ok(v),
104 Err(e) => io_error_kind_from_error(e),
105 }
106 }
107}
108
109#[must_use]
113pub enum NetworkResult<T> {
114 Timeout,
115 ServiceUnavailable(String),
116 NoConnection(io::Error),
117 AlreadyExists(io::Error),
118 InvalidMessage(String),
119 Value(T),
120}
121
122impl<T> NetworkResult<T> {
123 pub fn timeout() -> Self {
124 Self::Timeout
125 }
126 pub fn service_unavailable<S: ToString>(s: S) -> Self {
127 Self::ServiceUnavailable(s.to_string())
128 }
129 pub fn no_connection(e: io::Error) -> Self {
130 Self::NoConnection(e)
131 }
132 pub fn no_connection_other<S: ToString>(s: S) -> Self {
133 Self::NoConnection(io::Error::other(s.to_string()))
134 }
135 pub fn invalid_message<S: ToString>(s: S) -> Self {
136 Self::InvalidMessage(s.to_string())
137 }
138 pub fn already_exists(e: io::Error) -> Self {
139 Self::AlreadyExists(e)
140 }
141 pub fn value(value: T) -> Self {
142 Self::Value(value)
143 }
144
145 pub fn is_timeout(&self) -> bool {
146 matches!(self, Self::Timeout)
147 }
148 pub fn is_no_connection(&self) -> bool {
149 matches!(self, Self::NoConnection(_))
150 }
151 pub fn is_already_exists(&self) -> bool {
152 matches!(self, Self::AlreadyExists(_))
153 }
154 pub fn is_invalid_message(&self) -> bool {
155 matches!(self, Self::InvalidMessage(_))
156 }
157 pub fn is_value(&self) -> bool {
158 matches!(self, Self::Value(_))
159 }
160 pub fn map<X, F: Fn(T) -> X>(self, f: F) -> NetworkResult<X> {
161 match self {
162 Self::Timeout => NetworkResult::<X>::Timeout,
163 Self::ServiceUnavailable(s) => NetworkResult::<X>::ServiceUnavailable(s),
164 Self::NoConnection(e) => NetworkResult::<X>::NoConnection(e),
165 Self::AlreadyExists(e) => NetworkResult::<X>::AlreadyExists(e),
166 Self::InvalidMessage(s) => NetworkResult::<X>::InvalidMessage(s),
167 Self::Value(v) => NetworkResult::<X>::Value(f(v)),
168 }
169 }
170 pub fn into_io_result(self) -> Result<T, io::Error> {
171 match self {
172 Self::Timeout => Err(io::Error::new(io::ErrorKind::TimedOut, "Timed out")),
173 Self::ServiceUnavailable(s) => Err(io::Error::new(
174 io::ErrorKind::NotFound,
175 format!("Service unavailable: {}", s),
176 )),
177 Self::NoConnection(e) => Err(e),
178 Self::AlreadyExists(e) => Err(e),
179 Self::InvalidMessage(s) => Err(io::Error::new(
180 io::ErrorKind::InvalidData,
181 format!("Invalid message: {}", s),
182 )),
183 Self::Value(v) => Ok(v),
184 }
185 }
186}
187
188impl<T> From<NetworkResult<T>> for Option<T> {
189 fn from(t: NetworkResult<T>) -> Self {
190 match t {
191 NetworkResult::Value(v) => Some(v),
192 _ => None,
193 }
194 }
195}
196
197impl<T: Debug> Debug for NetworkResult<T> {
198 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
199 match self {
200 Self::Timeout => write!(f, "Timeout"),
201 Self::ServiceUnavailable(s) => f.debug_tuple("ServiceUnavailable").field(s).finish(),
202 Self::NoConnection(e) => f.debug_tuple("NoConnection").field(e).finish(),
203 Self::AlreadyExists(e) => f.debug_tuple("AlreadyExists").field(e).finish(),
204 Self::InvalidMessage(s) => f.debug_tuple("InvalidMessage").field(s).finish(),
205 Self::Value(v) => f.debug_tuple("Value").field(v).finish(),
206 }
207 }
208}
209
210impl<T> Display for NetworkResult<T> {
211 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
212 match self {
213 Self::Timeout => write!(f, "Timeout"),
214 Self::ServiceUnavailable(s) => write!(f, "ServiceUnavailable({})", s),
215 Self::NoConnection(e) => write!(f, "NoConnection({})", e.kind()),
216 Self::AlreadyExists(e) => write!(f, "AlreadyExists({})", e.kind()),
217 Self::InvalidMessage(s) => write!(f, "InvalidMessage({})", s),
218 Self::Value(_) => write!(f, "Value"),
219 }
220 }
221}
222
223impl<T: Debug + Display> Error for NetworkResult<T> {}
224
225#[macro_export]
229macro_rules! network_result_raise {
230 ($r: expr) => {
231 match $r {
232 NetworkResult::Timeout => return Ok(NetworkResult::Timeout),
233 NetworkResult::ServiceUnavailable(s) => return Ok(NetworkResult::ServiceUnavailable(s)),
234 NetworkResult::NoConnection(e) => return Ok(NetworkResult::NoConnection(e)),
235 NetworkResult::AlreadyExists(e) => return Ok(NetworkResult::AlreadyExists(e)),
236 NetworkResult::InvalidMessage(s) => return Ok(NetworkResult::InvalidMessage(s)),
237 NetworkResult::Value(_) => panic!("Can not raise value"),
238 }
239 };
240}
241
242#[macro_export]
243macro_rules! network_result_try {
244 ($r: expr) => {
245 match $r {
246 NetworkResult::Timeout => return Ok(NetworkResult::Timeout),
247 NetworkResult::ServiceUnavailable(s) => return Ok(NetworkResult::ServiceUnavailable(s)),
248 NetworkResult::NoConnection(e) => return Ok(NetworkResult::NoConnection(e)),
249 NetworkResult::AlreadyExists(e) => return Ok(NetworkResult::AlreadyExists(e)),
250 NetworkResult::InvalidMessage(s) => return Ok(NetworkResult::InvalidMessage(s)),
251 NetworkResult::Value(v) => v,
252 }
253 };
254 ($r:expr => $f:tt) => {
255 match $r {
256 NetworkResult::Timeout => {
257 $f;
258 return Ok(NetworkResult::Timeout);
259 }
260 NetworkResult::ServiceUnavailable(s) => {
261 $f;
262 return Ok(NetworkResult::ServiceUnavailable(s));
263 }
264 NetworkResult::NoConnection(e) => {
265 $f;
266 return Ok(NetworkResult::NoConnection(e));
267 }
268 NetworkResult::AlreadyExists(e) => {
269 $f;
270 return Ok(NetworkResult::AlreadyExists(e));
271 }
272 NetworkResult::InvalidMessage(s) => {
273 $f;
274 return Ok(NetworkResult::InvalidMessage(s));
275 }
276 NetworkResult::Value(v) => v,
277 }
278 };
279}