veilid_tools/
timeout_or.rs

1use super::*;
2
3use core::fmt::{Debug, Display};
4use core::result::Result;
5use std::error::Error;
6use std::io;
7
8#[derive(ThisError, Debug, Clone, Copy, Eq, PartialEq)]
9#[error("Timeout")]
10pub struct TimeoutError();
11
12impl TimeoutError {
13    #[must_use]
14    pub fn to_io(self) -> io::Error {
15        io::Error::new(io::ErrorKind::TimedOut, self)
16    }
17}
18
19cfg_if! {
20    if #[cfg(feature="rt-async-std")] {
21        impl From<async_std::future::TimeoutError> for TimeoutError {
22            fn from(_: async_std::future::TimeoutError) -> Self {
23                Self()
24            }
25        }
26    } else if #[cfg(feature="rt-tokio")] {
27        impl From<tokio::time::error::Elapsed> for TimeoutError {
28            fn from(_: tokio::time::error::Elapsed) -> Self {
29                Self()
30            }
31        }
32    }
33}
34
35//////////////////////////////////////////////////////////////////
36// Non-fallible timeout conversions
37
38pub trait TimeoutOrExt<T> {
39    fn into_timeout_or(self) -> TimeoutOr<T>;
40}
41
42impl<T> TimeoutOrExt<T> for Result<T, TimeoutError> {
43    fn into_timeout_or(self) -> TimeoutOr<T> {
44        self.ok()
45            .map(|v| TimeoutOr::<T>::Value(v))
46            .unwrap_or(TimeoutOr::<T>::Timeout)
47    }
48}
49
50pub trait IoTimeoutOrExt<T> {
51    fn into_timeout_or(self) -> io::Result<TimeoutOr<T>>;
52}
53
54impl<T> IoTimeoutOrExt<T> for io::Result<T> {
55    fn into_timeout_or(self) -> io::Result<TimeoutOr<T>> {
56        match self {
57            Ok(v) => Ok(TimeoutOr::<T>::Value(v)),
58            Err(e) if e.kind() == io::ErrorKind::TimedOut => Ok(TimeoutOr::<T>::Timeout),
59            Err(e) => Err(e),
60        }
61    }
62}
63
64pub trait TimeoutOrResultExt<T, E> {
65    fn into_result(self) -> Result<TimeoutOr<T>, E>;
66}
67
68impl<T, E> TimeoutOrResultExt<T, E> for TimeoutOr<Result<T, E>> {
69    fn into_result(self) -> Result<TimeoutOr<T>, E> {
70        match self {
71            TimeoutOr::<Result<T, E>>::Timeout => Ok(TimeoutOr::<T>::Timeout),
72            TimeoutOr::<Result<T, E>>::Value(Ok(v)) => Ok(TimeoutOr::<T>::Value(v)),
73            TimeoutOr::<Result<T, E>>::Value(Err(e)) => Err(e),
74        }
75    }
76}
77
78//////////////////////////////////////////////////////////////////
79// Non-fallible timeout
80
81#[must_use]
82pub enum TimeoutOr<T> {
83    Timeout,
84    Value(T),
85}
86
87impl<T> TimeoutOr<T> {
88    pub fn timeout() -> Self {
89        Self::Timeout
90    }
91    pub fn value(value: T) -> Self {
92        Self::Value(value)
93    }
94
95    pub fn is_timeout(&self) -> bool {
96        matches!(self, Self::Timeout)
97    }
98
99    pub fn is_value(&self) -> bool {
100        matches!(self, Self::Value(_))
101    }
102    pub fn map<X, F: Fn(T) -> X>(self, f: F) -> TimeoutOr<X> {
103        match self {
104            Self::Timeout => TimeoutOr::<X>::Timeout,
105            Self::Value(v) => TimeoutOr::<X>::Value(f(v)),
106        }
107    }
108    pub fn on_timeout<F: Fn()>(self, f: F) -> Self {
109        match self {
110            Self::Timeout => {
111                f();
112                Self::Timeout
113            }
114            Self::Value(v) => Self::Value(v),
115        }
116    }
117    pub fn into_timeout_error(self) -> Result<T, TimeoutError> {
118        match self {
119            Self::Timeout => Err(TimeoutError {}),
120            Self::Value(v) => Ok(v),
121        }
122    }
123
124    pub fn into_option(self) -> Option<T> {
125        match self {
126            Self::Timeout => None,
127            Self::Value(v) => Some(v),
128        }
129    }
130}
131
132impl<T> From<TimeoutOr<T>> for Option<T> {
133    fn from(t: TimeoutOr<T>) -> Self {
134        match t {
135            TimeoutOr::<T>::Timeout => None,
136            TimeoutOr::<T>::Value(v) => Some(v),
137        }
138    }
139}
140
141impl<T: Clone> Clone for TimeoutOr<T> {
142    fn clone(&self) -> Self {
143        match self {
144            Self::Timeout => Self::Timeout,
145            Self::Value(t) => Self::Value(t.clone()),
146        }
147    }
148}
149impl<T: Debug> Debug for TimeoutOr<T> {
150    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
151        match self {
152            Self::Timeout => write!(f, "Timeout"),
153            Self::Value(arg0) => f.debug_tuple("Value").field(arg0).finish(),
154        }
155    }
156}
157impl<T: Display> Display for TimeoutOr<T> {
158    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
159        match self {
160            Self::Timeout => write!(f, ""),
161            Self::Value(arg0) => write!(f, "{}", arg0),
162        }
163    }
164}
165impl<T: Debug + Display> Error for TimeoutOr<T> {}
166
167//////////////////////////////////////////////////////////////////
168// Non-fallible timeoue macros
169
170#[macro_export]
171macro_rules! timeout_or_try {
172    ($r: expr) => {
173        match $r {
174            TimeoutOr::Timeout => return Ok(TimeoutOr::Timeout),
175            TimeoutOr::Value(v) => v,
176        }
177    };
178}