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