about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDylan DPC <dylan.dpc@gmail.com>2020-05-09 03:10:01 +0200
committerGitHub <noreply@github.com>2020-05-09 03:10:01 +0200
commit62374ee4ad00a4cc8a4807ed13823a49e2e8422d (patch)
tree7f01d456117042d0970296ce9705acce68fd1667
parent7ebd87a7a1e0e21767422e115c9455ef6e6d4bee (diff)
parent029515d9164bddc0928c159d375aadfc7f256b28 (diff)
downloadrust-62374ee4ad00a4cc8a4807ed13823a49e2e8422d.tar.gz
rust-62374ee4ad00a4cc8a4807ed13823a49e2e8422d.zip
Rollup merge of #70834 - yoshuawuyts:future-pending-ready, r=sfackler
Add core::future::{pending,ready}

Adds two future constructors to `core`: `future::ready` and `future::pending`. These functions enable constructing futures of any type that either immediately resolve, or never resolve which is an incredible useful tool when writing documentation.

These functions have prior art in both the `futures` and `async-std` crates. This implementation has been adapted from the `futures` crate.

## Examples

In https://github.com/rust-lang/rust/pull/70817 we propose adding the `ready!` macro. In the example we use an `async fn` which does not return a future that implements `Unpin`, which leads to the use of `unsafe`. Instead had we had `future::ready` available, we could've written the same example without using `unsafe`:

```rust
use core::task::{Context, Poll};
use core::future::{self, Future};
use core::pin::Pin;

pub fn do_poll(cx: &mut Context<'_>) -> Poll<()> {
    let mut fut = future::ready(42_u8);
    let num = ready!(Pin::new(fut).poll(cx));
    // ... use num

    Poll::Ready(())
}
```

## Why future::ready?

Arguably `future::ready` and `async {}` can be considered equivalent. The main differences are that `future::ready` returns a future that implements `Unpin`, and the returned future is a concrete type. This is useful for traits that require a future as an associated type that can sometimes be a no-op ([example](https://docs.rs/http-service/0.4.0/http_service/trait.HttpService.html#associatedtype.ConnectionFuture)).

The final, minor argument is that `future::ready` and `future::pending` form a counterpart to the enum members of `Poll`: `Ready` and `Pending`. These functions form a conceptual bridge between `Poll` and `Future`, and can be used as a useful teaching device.

## References
- [`futures::future::ready`](https://docs.rs/futures/0.3.4/futures/future/fn.ready.html)
- [`futures::future::pending`](https://docs.rs/futures/0.3.4/futures/future/fn.pending.html)
- [`async_std::future::pending`](https://docs.rs/async-std/1.5.0/async_std/future/fn.pending.html)
- [`async_std::future::ready`](https://docs.rs/async-std/1.5.0/async_std/future/fn.ready.html)
-rw-r--r--src/libcore/future/mod.rs8
-rw-r--r--src/libcore/future/pending.rs57
-rw-r--r--src/libcore/future/ready.rs45
3 files changed, 110 insertions, 0 deletions
diff --git a/src/libcore/future/mod.rs b/src/libcore/future/mod.rs
index e7f681c2e94..b5a102916a0 100644
--- a/src/libcore/future/mod.rs
+++ b/src/libcore/future/mod.rs
@@ -10,9 +10,17 @@ use crate::{
 };
 
 mod future;
+mod pending;
+mod ready;
+
 #[stable(feature = "futures_api", since = "1.36.0")]
 pub use self::future::Future;
 
+#[unstable(feature = "future_readiness_fns", issue = "70921")]
+pub use pending::{pending, Pending};
+#[unstable(feature = "future_readiness_fns", issue = "70921")]
+pub use ready::{ready, Ready};
+
 /// This type is needed because:
 ///
 /// a) Generators cannot implement `for<'a, 'b> Generator<&'a mut Context<'b>>`, so we need to pass
diff --git a/src/libcore/future/pending.rs b/src/libcore/future/pending.rs
new file mode 100644
index 00000000000..74887b68aa0
--- /dev/null
+++ b/src/libcore/future/pending.rs
@@ -0,0 +1,57 @@
+use crate::future::Future;
+use crate::marker;
+use crate::pin::Pin;
+use crate::task::{Context, Poll};
+
+/// Creates a future which never resolves, representing a computation that never
+/// finishes.
+///
+/// This `struct` is created by the [`pending`] function. See its
+/// documentation for more.
+///
+/// [`pending`]: fn.pending.html
+#[unstable(feature = "future_readiness_fns", issue = "70921")]
+#[derive(Debug)]
+#[must_use = "futures do nothing unless you `.await` or poll them"]
+pub struct Pending<T> {
+    _data: marker::PhantomData<T>,
+}
+
+/// Creates a future which never resolves, representing a computation that never
+/// finishes.
+///
+/// # Examples
+///
+/// ```no_run
+/// #![feature(future_readiness_fns)]
+/// use core::future;
+///
+/// # async fn run() {
+/// let future = future::pending();
+/// let () = future.await;
+/// unreachable!();
+/// # }
+/// ```
+#[unstable(feature = "future_readiness_fns", issue = "70921")]
+pub fn pending<T>() -> Pending<T> {
+    Pending { _data: marker::PhantomData }
+}
+
+#[unstable(feature = "future_readiness_fns", issue = "70921")]
+impl<T> Future for Pending<T> {
+    type Output = T;
+
+    fn poll(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<T> {
+        Poll::Pending
+    }
+}
+
+#[unstable(feature = "future_readiness_fns", issue = "70921")]
+impl<T> Unpin for Pending<T> {}
+
+#[unstable(feature = "future_readiness_fns", issue = "70921")]
+impl<T> Clone for Pending<T> {
+    fn clone(&self) -> Self {
+        pending()
+    }
+}
diff --git a/src/libcore/future/ready.rs b/src/libcore/future/ready.rs
new file mode 100644
index 00000000000..31b39d7fb6c
--- /dev/null
+++ b/src/libcore/future/ready.rs
@@ -0,0 +1,45 @@
+use crate::future::Future;
+use crate::pin::Pin;
+use crate::task::{Context, Poll};
+
+/// Creates a future that is immediately ready with a value.
+///
+/// This `struct` is created by the [`ready`] function. See its
+/// documentation for more.
+///
+/// [`ready`]: fn.ready.html
+#[unstable(feature = "future_readiness_fns", issue = "70921")]
+#[derive(Debug, Clone)]
+#[must_use = "futures do nothing unless you `.await` or poll them"]
+pub struct Ready<T>(Option<T>);
+
+#[unstable(feature = "future_readiness_fns", issue = "70921")]
+impl<T> Unpin for Ready<T> {}
+
+#[unstable(feature = "future_readiness_fns", issue = "70921")]
+impl<T> Future for Ready<T> {
+    type Output = T;
+
+    #[inline]
+    fn poll(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<T> {
+        Poll::Ready(self.0.take().expect("Ready polled after completion"))
+    }
+}
+
+/// Creates a future that is immediately ready with a value.
+///
+/// # Examples
+///
+/// ```
+/// #![feature(future_readiness_fns)]
+/// use core::future;
+///
+/// # async fn run() {
+/// let a = future::ready(1);
+/// assert_eq!(a.await, 1);
+/// # }
+/// ```
+#[unstable(feature = "future_readiness_fns", issue = "70921")]
+pub fn ready<T>(t: T) -> Ready<T> {
+    Ready(Some(t))
+}