smoltimeout/lib.rs
1/* ┌────────────────────────────────────────────────────────────────────────────────────────────┐ *\
2 * │ │ *
3 * │ This Source Code Form is subject to the terms of the Mozilla Public │ *
4 * │ License, v. 2.0. If a copy of the MPL was not distributed with this │ *
5 * │ file, You can obtain one at http://mozilla.org/MPL/2.0/. │ *
6 * │ │ *
7\* └────────────────────────────────────────────────────────────────────────────────────────────┘ */
8
9/* ┌────────────────────────────────────────────────────────────────────────────────────────────┐ *\
10 * │ Configuration │ *
11\* └────────────────────────────────────────────────────────────────────────────────────────────┘ */
12
13// This is completely useless: due to this library depends async-io (it is not optional), and async-io uses std. so the final generated native code is still linked to std.
14//#![no_std]
15
16/* ┌────────────────────────────────────────────────────────────────────────────────────────────┐ *\
17 * │ Documentation │ *
18\* └────────────────────────────────────────────────────────────────────────────────────────────┘ */
19
20//! A way to poll a future until it or a timer completes.
21//!
22//! ## Example
23//! see [`TimeoutExt::timeout`] and [`TimeoutExt::deadline`].
24
25/* ┌────────────────────────────────────────────────────────────────────────────────────────────┐ *\
26 * │ Imports │ *
27\* └────────────────────────────────────────────────────────────────────────────────────────────┘ */
28
29use async_io::Timer;
30use core::future::Future;
31use core::pin::Pin;
32use core::task::{Context, Poll};
33use std::time::{Instant, Duration};
34use pin_project_lite::pin_project;
35
36/* ┌────────────────────────────────────────────────────────────────────────────────────────────┐ *\
37 * │ struct Timed<Fut> │ *
38\* └────────────────────────────────────────────────────────────────────────────────────────────┘ */
39
40pin_project! {
41 /// A helper that polling both inner Future, and a [`Timer`] that will complete after a specified
42 /// timeout or deadline.
43 ///
44 /// ## Example
45 /// see [`TimeoutExt::timeout`] and [`TimeoutExt::deadline`].
46 #[derive(Debug)]
47 pub struct Timed<Fut: Future> {
48 #[pin]
49 future: Fut,
50 #[pin]
51 timer: Timer,
52 }
53}
54
55/* ┌────────────────────────────────────────────────────────────────────────────────────────────┐ *\
56 * │ trait TimeoutExt: Future │ *
57\* └────────────────────────────────────────────────────────────────────────────────────────────┘ */
58
59/// An extension trait for [`Future`]s that provides a way to create [`Timeout`]s.
60pub trait TimedExt: Future {
61 /// Given a [`Duration`], creates and returns a new [`Timed`] that will poll both the Future, and a [`Timer`] that will complete after the provided duration.
62 /// * first polling the Future, returns it's output if any.
63 /// * then polling the Timer, and fallback to [`None`] if the Timer completes.
64 ///
65 /// ## Example
66 ///
67 /// ```rust
68 /// use async_io::Timer;
69 /// # use futures_lite::future;
70 /// use smoltimeout::TimeoutExt;
71 /// use std::time::Duration;
72 ///
73 /// # future::block_on(async {
74 /// #
75 /// let mut timer = Timer::after(Duration::from_millis(250));
76 /// let foo = async {
77 /// timer.await;
78 /// 24
79 /// }.timeout(Duration::from_millis(100));
80 /// assert_eq!(foo.await, None);
81 ///
82 /// timer = Timer::after(Duration::from_millis(100));
83 /// let bar = async move {
84 /// timer.await;
85 /// 42
86 /// }.timeout(Duration::from_millis(250));
87 /// assert_eq!(bar.await, Some(42));
88 ///
89 /// timer = Timer::after(Duration::from_millis(50));
90 /// let mod_of_delta4 = async move {
91 /// timer.await;
92 /// (21*2) as f64
93 /// }.timeout(Duration::from_millis(0));
94 /// Timer::after(Duration::from_millis(100)).await;
95 /// assert_eq!(mod_of_delta4.await, Some(42.0));
96 /// #
97 /// # })
98 /// ```
99 fn timeout(self, after: Duration) -> Timed<Self>
100 where
101 Self: Sized,
102 {
103 Timed {
104 future: self,
105 timer: Timer::after(after),
106 }
107 }
108
109 /// Given a [`Instant`], creates and returns a new [`Timed`] that will poll both the Future
110 /// and a [`Timer`] that will complete after the provided deadline.
111 /// * first polling the Future, returns it's output if any.
112 /// * then polling the Timer, and fallback to [`None`] if the Timer completes.
113 ///
114 /// ## Example
115 ///
116 /// ```rust
117 /// use async_io::Timer;
118 /// # use futures_lite::future;
119 /// use smoltimeout::TimeoutExt;
120 /// use std::time::{Instant, Duration};
121 ///
122 /// # future::block_on(async {
123 /// #
124 /// let mut timer = Timer::after(Duration::from_millis(250));
125 /// let foo = async move {
126 /// timer.await;
127 /// 24
128 /// }.deadline(Instant::now() + Duration::from_millis(100));
129 /// assert_eq!(foo.await, None);
130 ///
131 /// timer = Timer::after(Duration::from_millis(100));
132 /// let bar = async move {
133 /// timer.await;
134 /// 42
135 /// }.deadline(Instant::now() + Duration::from_millis(250));
136 /// assert_eq!(bar.await, Some(42));
137 ///
138 /// timer = Timer::after(Duration::from_millis(50));
139 /// let mod_of_delta4 = async move {
140 /// timer.await;
141 /// (21*2) as f64
142 /// }.deadline(Instant::now());
143 /// Timer::after(Duration::from_millis(100)).await;
144 /// assert_eq!(mod_of_delta4.await, Some(42.0));
145 /// #
146 /// # })
147 /// ```
148 fn deadline(self, deadline: Instant) -> Timed<Self>
149 where
150 Self: Sized,
151 {
152 Timed {
153 future: self,
154 timer: Timer::at(deadline),
155 }
156 }
157}
158
159impl<Fut: Future> TimedExt for Fut {}
160
161/// for provide compatibly to older versions.
162pub use {
163 TimedExt as TimeoutExt,
164 Timed as Timeout,
165};
166
167/* ┌────────────────────────────────────────────────────────────────────────────────────────────┐ *\
168 * │ impl Future for Timeout<Fut> │ *
169\* └────────────────────────────────────────────────────────────────────────────────────────────┘ */
170
171impl<Fut: Future> Future for Timed<Fut> {
172 type Output = Option<Fut::Output>;
173
174 fn poll(self: Pin<&mut Self>, ctx: &mut Context) -> Poll<Self::Output> {
175 let this = self.project();
176
177 if let Poll::Ready(output) = this.future.poll(ctx) {
178 return Poll::Ready(Some(output));
179 }
180
181 if this.timer.poll(ctx).is_ready() {
182 return Poll::Ready(None);
183 }
184
185 Poll::Pending
186 }
187}