veilid_tools/
timeout_or.rs1use 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
35pub 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#[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#[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}