timer_kit/timeout.rs
1use std::{future::Future, pin::Pin, task::Poll, time::Duration};
2
3use pin_project_lite::pin_project;
4
5use crate::{error::Elapsed, Delay};
6
7/// Creates a new `Timeout` with a specified duration.
8///
9/// # Example
10///
11/// Creates a timeout with smol's timer
12///
13/// ```rust,no_run
14/// use std::time::Duration;
15/// use timer_kit::timeout;
16///
17/// let result = timeout::<smol::Timer, _>(Duration::from_millis(100), async { }).await;
18/// ```
19///
20/// Creates a timeout with `fluvio_wasm_timer::Delay`
21///
22/// ```rust,no_run
23/// use std::time::Duration;
24/// use timer_kit::timeout;
25///
26/// let result = timeout::<fluvio_wasm_timer::Delay, _>(Duration::from_millis(100), async { }).await;
27/// ```
28pub fn timeout<D, Fut>(duration: Duration, fut: Fut) -> Timeout<D, Fut>
29where
30 D: Delay,
31 Fut: Future,
32{
33 Timeout::new(duration, fut)
34}
35
36/// Creates a new `Timeout` with a specified deadline.
37///
38/// # Example
39///
40/// Creates a timeout with smol's timer
41///
42/// ```rust,no_run
43/// use std::time::{Duration, Instant};
44/// use timer_kit::timeout_at;
45///
46/// let result = timeout_at::<smol::Timer, _>(Instant::now() + Duration::from_millis(100), async { }).await;
47/// ```
48///
49/// Creates a timeout with `fluvio_wasm_timer::Delay`
50///
51/// ```rust,no_run
52/// use std::time::{Duration};
53/// use fluent_wasm_timer::Instant;
54/// use timer_kit::timeout_at;
55///
56/// let result = timeout_at::<fluvio_wasm_timer::Delay, _>(Instant::now() + Duration::from_millis(100), async { }).await;
57/// ```
58pub fn timeout_at<D, Fut>(deadline: D::Instant, fut: Fut) -> Timeout<D, Fut>
59where
60 D: Delay,
61 Fut: Future,
62{
63 Timeout::new_at(deadline, fut)
64}
65
66pin_project! {
67 /// A timeout future.
68 ///
69 /// It returns `<Fut as Future>::Output` if the future completes before the timeout or
70 /// [`Elapsed`] if the timeout elapses before the future completes.
71 ///
72 /// # Warning - Exhaustion
73 ///
74 /// This future is not able to avoid exhaustion if the future never completes and never returns
75 /// `Pending`. The user should ensure that the `Fut` future is able to return `Pending` at some
76 /// point to avoid exhaustion.
77 pub struct Timeout<D, Fut> {
78 #[pin]
79 delay: D,
80
81 #[pin]
82 future: Fut,
83 }
84}
85
86impl<D, Fut> Timeout<D, Fut>
87where
88 D: Delay,
89 Fut: Future,
90{
91 /// Creates a new `Timeout` with a specified duration.
92 ///
93 /// # Example
94 ///
95 /// Creates a timeout with smol's timer
96 ///
97 /// ```rust,no_run
98 /// use std::time::Duration;
99 /// use timer_kit::Timeout;
100 ///
101 /// let result = Timeout::<smol::Timer, _>::new(Duration::from_millis(100), async {}).await;
102 /// ```
103 ///
104 /// Creates a timeout with `fluvio_wasm_timer::Delay`
105 ///
106 /// ```rust,no_run
107 /// use std::time::Duration;
108 /// use timer_kit::Timeout;
109 ///
110 /// let result = Timeout::<fluvio_wasm_timer::Delay, _>::new(Duration::from_millis(100), async {}).await;
111 /// ```
112 pub fn new(duration: Duration, future: Fut) -> Self {
113 Self {
114 delay: D::delay(duration),
115 future,
116 }
117 }
118
119 /// Creates a new `Timeout` with a specified deadline.
120 ///
121 /// # Example
122 ///
123 /// Creates a timeout with smol's timer
124 ///
125 /// ```rust,no_run
126 /// use std::time::{Duration, Instant};
127 /// use timer_kit::Timeout;
128 ///
129 /// let result = Timeout::<smol::Timer, _>::new_at(Instant::now() + Duration::from_millis(100), async {}).await;
130 /// ```
131 ///
132 /// Creates a timeout with `fluvio_wasm_timer::Delay`
133 ///
134 /// ```rust,no_run
135 /// use std::time::Duration;
136 /// use fluent_wasm_timer::Instant;
137 /// use timer_kit::Timeout;
138 ///
139 /// let result = Timeout::<fluvio_wasm_timer::Delay, _>::new_at(Instant::now() + Duration::from_millis(100), async {}).await;
140 /// ```
141 pub fn new_at(deadline: D::Instant, future: Fut) -> Self {
142 Self {
143 delay: D::delay_until(deadline),
144 future,
145 }
146 }
147}
148
149impl<D, Fut> Future for Timeout<D, Fut>
150where
151 D: Delay,
152 Fut: Future,
153{
154 type Output = Result<Fut::Output, Elapsed>;
155
156 fn poll(
157 self: Pin<&mut Self>,
158 cx: &mut std::task::Context<'_>,
159 ) -> std::task::Poll<Self::Output> {
160 let mut this = self.project();
161
162 if let Poll::Ready(output) = this.future.poll(cx) {
163 return Poll::Ready(Ok(output));
164 }
165
166 match this.delay.as_mut().poll_elapsed(cx) {
167 Poll::Ready(_) => Poll::Ready(Err(Elapsed::new())),
168 Poll::Pending => Poll::Pending,
169 }
170 }
171}