Skip to content

Commit 4e76cc2

Browse files
committed
flatten top-level stubs
1 parent b09df47 commit 4e76cc2

File tree

20 files changed

+502
-505
lines changed

20 files changed

+502
-505
lines changed

src/future.rs

Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
1+
//! Asynchronous values.
2+
//!
3+
//! # Cancellation
4+
//!
5+
//! Futures can be cancelled by dropping them before they finish executing. This
6+
//! is useful when we're no longer interested in the result of an operation, as
7+
//! it allows us to stop doing needless work. This also means that a future may cancel at any `.await` point, and so just
8+
//! like with `?` we have to be careful to roll back local state if our future
9+
//! halts there.
10+
//!
11+
//!
12+
//! ```no_run
13+
//! use futures_lite::prelude::*;
14+
//! use wstd::prelude::*;
15+
//! use wstd::time::Duration;
16+
//!
17+
//! #[wstd::main]
18+
//! async fn main() {
19+
//! let mut counter = 0;
20+
//! let value = async { "meow" }
21+
//! .delay(Duration::from_millis(100))
22+
//! .timeout(Duration::from_millis(200))
23+
//! .await;
24+
//!
25+
//! assert_eq!(value.unwrap(), "meow");
26+
//! }
27+
//! ```
28+
29+
use std::future::Future;
30+
use std::io;
31+
use std::pin::Pin;
32+
use std::task::{Context, Poll, ready};
33+
34+
use pin_project_lite::pin_project;
35+
36+
use crate::time::utils::timeout_err;
37+
38+
pub use self::future_ext::FutureExt;
39+
40+
// ---- Delay ----
41+
42+
pin_project! {
43+
/// Suspends a future until the specified deadline.
44+
///
45+
/// This `struct` is created by the [`delay`] method on [`FutureExt`]. See its
46+
/// documentation for more.
47+
///
48+
/// [`delay`]: crate::future::FutureExt::delay
49+
/// [`FutureExt`]: crate::future::futureExt
50+
#[must_use = "futures do nothing unless polled or .awaited"]
51+
pub struct Delay<F, D> {
52+
#[pin]
53+
future: F,
54+
#[pin]
55+
deadline: D,
56+
state: DelayState,
57+
}
58+
}
59+
60+
/// The internal state
61+
#[derive(Debug)]
62+
enum DelayState {
63+
Started,
64+
PollFuture,
65+
Completed,
66+
}
67+
68+
impl<F, D> Delay<F, D> {
69+
fn new(future: F, deadline: D) -> Self {
70+
Self {
71+
future,
72+
deadline,
73+
state: DelayState::Started,
74+
}
75+
}
76+
}
77+
78+
impl<F: Future, D: Future> Future for Delay<F, D> {
79+
type Output = F::Output;
80+
81+
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
82+
let mut this = self.project();
83+
loop {
84+
match this.state {
85+
DelayState::Started => {
86+
ready!(this.deadline.as_mut().poll(cx));
87+
*this.state = DelayState::PollFuture;
88+
}
89+
DelayState::PollFuture => {
90+
let value = ready!(this.future.as_mut().poll(cx));
91+
*this.state = DelayState::Completed;
92+
return Poll::Ready(value);
93+
}
94+
DelayState::Completed => panic!("future polled after completing"),
95+
}
96+
}
97+
}
98+
}
99+
100+
// ---- Timeout ----
101+
102+
pin_project! {
103+
/// A future that times out after a duration of time.
104+
///
105+
/// This `struct` is created by the [`timeout`] method on [`FutureExt`]. See its
106+
/// documentation for more.
107+
///
108+
/// [`timeout`]: crate::future::FutureExt::timeout
109+
/// [`FutureExt`]: crate::future::futureExt
110+
#[must_use = "futures do nothing unless polled or .awaited"]
111+
pub struct Timeout<F, D> {
112+
#[pin]
113+
future: F,
114+
#[pin]
115+
deadline: D,
116+
completed: bool,
117+
}
118+
}
119+
120+
impl<F, D> Timeout<F, D> {
121+
fn new(future: F, deadline: D) -> Self {
122+
Self {
123+
future,
124+
deadline,
125+
completed: false,
126+
}
127+
}
128+
}
129+
130+
impl<F: Future, D: Future> Future for Timeout<F, D> {
131+
type Output = io::Result<F::Output>;
132+
133+
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
134+
let this = self.project();
135+
136+
assert!(!*this.completed, "future polled after completing");
137+
138+
match this.future.poll(cx) {
139+
Poll::Ready(v) => {
140+
*this.completed = true;
141+
Poll::Ready(Ok(v))
142+
}
143+
Poll::Pending => match this.deadline.poll(cx) {
144+
Poll::Ready(_) => {
145+
*this.completed = true;
146+
Poll::Ready(Err(timeout_err("future timed out")))
147+
}
148+
Poll::Pending => Poll::Pending,
149+
},
150+
}
151+
}
152+
}
153+
154+
// ---- FutureExt ----
155+
156+
mod future_ext {
157+
use super::{Delay, Timeout};
158+
use std::future::{Future, IntoFuture};
159+
160+
/// Extend `Future` with time-based operations.
161+
pub trait FutureExt: Future {
162+
/// Return an error if a future does not complete within a given time span.
163+
///
164+
/// Typically timeouts are, as the name implies, based on _time_. However
165+
/// this method can time out based on any future. This can be useful in
166+
/// combination with channels, as it allows (long-lived) futures to be
167+
/// cancelled based on some external event.
168+
///
169+
/// When a timeout is returned, the future will be dropped and destructors
170+
/// will be run.
171+
///
172+
/// # Example
173+
///
174+
/// ```no_run
175+
/// use wstd::prelude::*;
176+
/// use wstd::time::{Instant, Duration};
177+
/// use std::io;
178+
///
179+
/// #[wstd::main]
180+
/// async fn main() {
181+
/// let res = async { "meow" }
182+
/// .delay(Duration::from_millis(100)) // longer delay
183+
/// .timeout(Duration::from_millis(50)) // shorter timeout
184+
/// .await;
185+
/// assert_eq!(res.unwrap_err().kind(), io::ErrorKind::TimedOut); // error
186+
///
187+
/// let res = async { "meow" }
188+
/// .delay(Duration::from_millis(50)) // shorter delay
189+
/// .timeout(Duration::from_millis(100)) // longer timeout
190+
/// .await;
191+
/// assert_eq!(res.unwrap(), "meow"); // success
192+
/// }
193+
/// ```
194+
fn timeout<D>(self, deadline: D) -> Timeout<Self, D::IntoFuture>
195+
where
196+
Self: Sized,
197+
D: IntoFuture,
198+
{
199+
Timeout::new(self, deadline.into_future())
200+
}
201+
202+
/// Delay resolving the future until the given deadline.
203+
///
204+
/// The underlying future will not be polled until the deadline has expired. In addition
205+
/// to using a time source as a deadline, any future can be used as a
206+
/// deadline too. When used in combination with a multi-consumer channel,
207+
/// this method can be used to synchronize the start of multiple futures and streams.
208+
///
209+
/// # Example
210+
///
211+
/// ```no_run
212+
/// use wstd::prelude::*;
213+
/// use wstd::time::{Instant, Duration};
214+
///
215+
/// #[wstd::main]
216+
/// async fn main() {
217+
/// let now = Instant::now();
218+
/// let delay = Duration::from_millis(100);
219+
/// let _ = async { "meow" }.delay(delay).await;
220+
/// assert!(now.elapsed() >= delay);
221+
/// }
222+
/// ```
223+
fn delay<D>(self, deadline: D) -> Delay<Self, D::IntoFuture>
224+
where
225+
Self: Sized,
226+
D: IntoFuture,
227+
{
228+
Delay::new(self, deadline.into_future())
229+
}
230+
}
231+
232+
impl<T> FutureExt for T where T: Future {}
233+
}

src/future/delay.rs

Lines changed: 0 additions & 63 deletions
This file was deleted.

src/future/future_ext.rs

Lines changed: 0 additions & 76 deletions
This file was deleted.

0 commit comments

Comments
 (0)