use super::*; use core::fmt::{Debug, Display}; use core::result::Result; use std::error::Error; use std::io; #[derive(ThisError, Debug, Clone, Copy, Eq, PartialEq)] #[error("Timeout")] pub struct TimeoutError(); impl TimeoutError { pub fn to_io(self) -> io::Error { io::Error::new(io::ErrorKind::TimedOut, self) } } cfg_if! { if #[cfg(feature="rt-async-std")] { impl From for TimeoutError { fn from(_: async_std::future::TimeoutError) -> Self { Self() } } } else if #[cfg(feature="rt-tokio")] { impl From for TimeoutError { fn from(_: tokio::time::error::Elapsed) -> Self { Self() } } } } ////////////////////////////////////////////////////////////////// // Non-fallible timeout conversions pub trait TimeoutOrExt { fn into_timeout_or(self) -> TimeoutOr; } impl TimeoutOrExt for Result { fn into_timeout_or(self) -> TimeoutOr { self.ok() .map(|v| TimeoutOr::::Value(v)) .unwrap_or(TimeoutOr::::Timeout) } } pub trait IoTimeoutOrExt { fn into_timeout_or(self) -> io::Result>; } impl IoTimeoutOrExt for io::Result { fn into_timeout_or(self) -> io::Result> { match self { Ok(v) => Ok(TimeoutOr::::Value(v)), Err(e) if e.kind() == io::ErrorKind::TimedOut => Ok(TimeoutOr::::Timeout), Err(e) => Err(e), } } } pub trait TimeoutOrResultExt { fn into_result(self) -> Result, E>; } impl TimeoutOrResultExt for TimeoutOr> { fn into_result(self) -> Result, E> { match self { TimeoutOr::>::Timeout => Ok(TimeoutOr::::Timeout), TimeoutOr::>::Value(Ok(v)) => Ok(TimeoutOr::::Value(v)), TimeoutOr::>::Value(Err(e)) => Err(e), } } } ////////////////////////////////////////////////////////////////// // Non-fallible timeout #[must_use] pub enum TimeoutOr { Timeout, Value(T), } impl TimeoutOr { pub fn timeout() -> Self { Self::Timeout } pub fn value(value: T) -> Self { Self::Value(value) } pub fn is_timeout(&self) -> bool { matches!(self, Self::Timeout) } pub fn is_value(&self) -> bool { matches!(self, Self::Value(_)) } pub fn map X>(self, f: F) -> TimeoutOr { match self { Self::Timeout => TimeoutOr::::Timeout, Self::Value(v) => TimeoutOr::::Value(f(v)), } } pub fn on_timeout(self, f: F) -> Self { match self { Self::Timeout => { f(); Self::Timeout } Self::Value(v) => Self::Value(v), } } pub fn into_timeout_error(self) -> Result { match self { Self::Timeout => Err(TimeoutError {}), Self::Value(v) => Ok(v), } } pub fn into_option(self) -> Option { match self { Self::Timeout => None, Self::Value(v) => Some(v), } } } impl From> for Option { fn from(t: TimeoutOr) -> Self { match t { TimeoutOr::::Timeout => None, TimeoutOr::::Value(v) => Some(v), } } } impl Clone for TimeoutOr { fn clone(&self) -> Self { match self { Self::Timeout => Self::Timeout, Self::Value(t) => Self::Value(t.clone()), } } } impl Debug for TimeoutOr { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match self { Self::Timeout => write!(f, "Timeout"), Self::Value(arg0) => f.debug_tuple("Value").field(arg0).finish(), } } } impl Display for TimeoutOr { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::Timeout => write!(f, ""), Self::Value(arg0) => write!(f, "{}", arg0), } } } impl Error for TimeoutOr {} ////////////////////////////////////////////////////////////////// // Non-fallible timeoue macros #[macro_export] macro_rules! timeout_or_try { ($r: expr) => { match $r { TimeoutOr::Timeout => return Ok(TimeoutOr::Timeout), TimeoutOr::Value(v) => v, } }; }