use super::*; use core::fmt::{Debug, Display}; use core::result::Result; use std::error::Error; use std::io; ////////////////////////////////////////////////////////////////// // Non-fallible network results conversions pub trait NetworkResultExt { fn into_network_result(self) -> NetworkResult; } impl NetworkResultExt for Result { fn into_network_result(self) -> NetworkResult { self.ok() .map(|v| NetworkResult::::Value(v)) .unwrap_or(NetworkResult::::Timeout) } } pub trait IoNetworkResultExt { fn into_network_result(self) -> io::Result>; } impl IoNetworkResultExt for io::Result { fn into_network_result(self) -> io::Result> { match self { Ok(v) => Ok(NetworkResult::Value(v)), #[cfg(feature = "io_error_more")] Err(e) => match e.kind() { io::ErrorKind::TimedOut => Ok(NetworkResult::Timeout), io::ErrorKind::ConnectionAborted | io::ErrorKind::ConnectionRefused | io::ErrorKind::ConnectionReset | io::ErrorKind::HostUnreachable | io::ErrorKind::NetworkUnreachable => Ok(NetworkResult::NoConnection(e)), _ => Err(e), }, #[cfg(not(feature = "io_error_more"))] Err(e) => match e.kind() { io::ErrorKind::TimedOut => Ok(NetworkResult::Timeout), io::ErrorKind::ConnectionAborted | io::ErrorKind::ConnectionRefused | io::ErrorKind::ConnectionReset => Ok(NetworkResult::NoConnection(e)), _ => Err(e), }, } } } pub trait NetworkResultResultExt { fn into_result_network_result(self) -> Result, E>; } impl NetworkResultResultExt for NetworkResult> { fn into_result_network_result(self) -> Result, E> { match self { NetworkResult::Timeout => Ok(NetworkResult::::Timeout), NetworkResult::NoConnection(e) => Ok(NetworkResult::::NoConnection(e)), NetworkResult::Value(Ok(v)) => Ok(NetworkResult::::Value(v)), NetworkResult::Value(Err(e)) => Err(e), } } } pub trait FoldedNetworkResultExt { fn folded(self) -> io::Result>; } impl FoldedNetworkResultExt for io::Result> { fn folded(self) -> io::Result> { match self { Ok(TimeoutOr::Timeout) => Ok(NetworkResult::Timeout), Ok(TimeoutOr::Value(v)) => Ok(NetworkResult::Value(v)), #[cfg(feature = "io_error_more")] Err(e) => match e.kind() { io::ErrorKind::TimedOut => Ok(NetworkResult::Timeout), io::ErrorKind::ConnectionAborted | io::ErrorKind::ConnectionRefused | io::ErrorKind::ConnectionReset | io::ErrorKind::HostUnreachable | io::ErrorKind::NetworkUnreachable => Ok(NetworkResult::NoConnection(e)), _ => Err(e), }, #[cfg(not(feature = "io_error_more"))] Err(e) => match e.kind() { io::ErrorKind::TimedOut => Ok(NetworkResult::Timeout), io::ErrorKind::ConnectionAborted | io::ErrorKind::ConnectionRefused | io::ErrorKind::ConnectionReset => Ok(NetworkResult::NoConnection(e)), _ => Err(e), }, } } } impl FoldedNetworkResultExt for io::Result> { fn folded(self) -> io::Result> { match self { Ok(v) => Ok(v), #[cfg(feature = "io_error_more")] Err(e) => match e.kind() { io::ErrorKind::TimedOut => Ok(NetworkResult::Timeout), io::ErrorKind::ConnectionAborted | io::ErrorKind::ConnectionRefused | io::ErrorKind::ConnectionReset | io::ErrorKind::HostUnreachable | io::ErrorKind::NetworkUnreachable => Ok(NetworkResult::NoConnection(e)), _ => Err(e), }, #[cfg(not(feature = "io_error_more"))] Err(e) => match e.kind() { io::ErrorKind::TimedOut => Ok(NetworkResult::Timeout), io::ErrorKind::ConnectionAborted | io::ErrorKind::ConnectionRefused | io::ErrorKind::ConnectionReset => Ok(NetworkResult::NoConnection(e)), _ => Err(e), }, } } } ////////////////////////////////////////////////////////////////// // Non-fallible network result pub enum NetworkResult { Timeout, NoConnection(io::Error), Value(T), } impl NetworkResult { pub fn timeout() -> Self { Self::Timeout } pub fn no_connection(e: io::Error) -> Self { Self::NoConnection(e) } pub fn value(value: T) -> Self { Self::Value(value) } pub fn is_timeout(&self) -> bool { matches!(self, Self::Timeout) } pub fn is_no_connection(&self) -> bool { matches!(self, Self::NoConnection(_)) } pub fn is_value(&self) -> bool { matches!(self, Self::Value(_)) } pub fn into_result(self) -> Result { match self { Self::Timeout => Err(io::Error::new(io::ErrorKind::TimedOut, "Timed out")), Self::NoConnection(e) => Err(e), Self::Value(v) => Ok(v), } } } impl From> for Option { fn from(t: NetworkResult) -> Self { match t { NetworkResult::Value(v) => Some(v), _ => None, } } } // impl Clone for NetworkResult { // fn clone(&self) -> Self { // match self { // Self::Timeout => Self::Timeout, // Self::NoConnection(e) => Self::NoConnection(e.clone()), // Self::Value(t) => Self::Value(t.clone()), // } // } // } impl Debug for NetworkResult { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match self { Self::Timeout => write!(f, "Timeout"), Self::NoConnection(e) => f.debug_tuple("NoConnection").field(e).finish(), Self::Value(v) => f.debug_tuple("Value").field(v).finish(), } } } impl Display for NetworkResult { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::Timeout => write!(f, ""), Self::NoConnection(e) => write!(f, "No connection: {}", e.kind()), Self::Value(v) => write!(f, "{}", v), } } } impl Error for NetworkResult {} ////////////////////////////////////////////////////////////////// // Non-fallible network result macros #[macro_export] macro_rules! network_result_try { ($r: expr) => { match $r { NetworkResult::Timeout => return Ok(NetworkResult::Timeout), NetworkResult::NoConnection(e) => return Ok(NetworkResult::NoConnection(e)), NetworkResult::Value(v) => v, } }; }