mirror of https://github.com/rust-lang/async-book
164 lines
4.9 KiB
Rust
164 lines
4.9 KiB
Rust
// ANCHOR: simple_future
|
|
trait SimpleFuture {
|
|
type Output;
|
|
fn poll(&mut self, wake: fn()) -> Poll<Self::Output>;
|
|
}
|
|
|
|
enum Poll<T> {
|
|
Ready(T),
|
|
Pending,
|
|
}
|
|
// ANCHOR_END: simple_future
|
|
|
|
struct Socket;
|
|
impl Socket {
|
|
fn has_data_to_read(&self) -> bool {
|
|
// check if the socket is currently readable
|
|
true
|
|
}
|
|
fn read_buf(&self) -> Vec<u8> {
|
|
// Read data in from the socket
|
|
vec![]
|
|
}
|
|
fn set_readable_callback(&self, _wake: fn()) {
|
|
// register `_wake` with something that will call it
|
|
// once the socket becomes readable, such as an
|
|
// `epoll`-based event loop.
|
|
}
|
|
}
|
|
|
|
// ANCHOR: socket_read
|
|
pub struct SocketRead<'a> {
|
|
socket: &'a Socket,
|
|
}
|
|
|
|
impl SimpleFuture for SocketRead<'_> {
|
|
type Output = Vec<u8>;
|
|
|
|
fn poll(&mut self, wake: fn()) -> Poll<Self::Output> {
|
|
if self.socket.has_data_to_read() {
|
|
// The socket has data -- read it into a buffer and return it.
|
|
Poll::Ready(self.socket.read_buf())
|
|
} else {
|
|
// The socket does not yet have data.
|
|
//
|
|
// Arrange for `wake` to be called once data is available.
|
|
// When data becomes available, `wake` will be called, and the
|
|
// user of this `Future` will know to call `poll` again and
|
|
// receive data.
|
|
self.socket.set_readable_callback(wake);
|
|
Poll::Pending
|
|
}
|
|
}
|
|
}
|
|
// ANCHOR_END: socket_read
|
|
|
|
// ANCHOR: join
|
|
/// A SimpleFuture that runs two other futures to completion concurrently.
|
|
///
|
|
/// Concurrency is achieved via the fact that calls to `poll` each future
|
|
/// may be interleaved, allowing each future to advance itself at its own pace.
|
|
pub struct Join<FutureA, FutureB> {
|
|
// Each field may contain a future that should be run to completion.
|
|
// If the future has already completed, the field is set to `None`.
|
|
// This prevents us from polling a future after it has completed, which
|
|
// would violate the contract of the `Future` trait.
|
|
a: Option<FutureA>,
|
|
b: Option<FutureB>,
|
|
}
|
|
|
|
impl<FutureA, FutureB> SimpleFuture for Join<FutureA, FutureB>
|
|
where
|
|
FutureA: SimpleFuture<Output = ()>,
|
|
FutureB: SimpleFuture<Output = ()>,
|
|
{
|
|
type Output = ();
|
|
fn poll(&mut self, wake: fn()) -> Poll<Self::Output> {
|
|
// Attempt to complete future `a`.
|
|
if let Some(a) = &mut self.a {
|
|
if let Poll::Ready(()) = a.poll(wake) {
|
|
self.a.take();
|
|
}
|
|
}
|
|
|
|
// Attempt to complete future `b`.
|
|
if let Some(b) = &mut self.b {
|
|
if let Poll::Ready(()) = b.poll(wake) {
|
|
self.b.take();
|
|
}
|
|
}
|
|
|
|
if self.a.is_none() && self.b.is_none() {
|
|
// Both futures have completed -- we can return successfully
|
|
Poll::Ready(())
|
|
} else {
|
|
// One or both futures returned `Poll::Pending` and still have
|
|
// work to do. They will call `wake()` when progress can be made.
|
|
Poll::Pending
|
|
}
|
|
}
|
|
}
|
|
// ANCHOR_END: join
|
|
|
|
// ANCHOR: and_then
|
|
/// A SimpleFuture that runs two futures to completion, one after another.
|
|
//
|
|
// Note: for the purposes of this simple example, `AndThenFut` assumes both
|
|
// the first and second futures are available at creation-time. The real
|
|
// `AndThen` combinator allows creating the second future based on the output
|
|
// of the first future, like `get_breakfast.and_then(|food| eat(food))`.
|
|
pub struct AndThenFut<FutureA, FutureB> {
|
|
first: Option<FutureA>,
|
|
second: FutureB,
|
|
}
|
|
|
|
impl<FutureA, FutureB> SimpleFuture for AndThenFut<FutureA, FutureB>
|
|
where
|
|
FutureA: SimpleFuture<Output = ()>,
|
|
FutureB: SimpleFuture<Output = ()>,
|
|
{
|
|
type Output = ();
|
|
fn poll(&mut self, wake: fn()) -> Poll<Self::Output> {
|
|
if let Some(first) = &mut self.first {
|
|
match first.poll(wake) {
|
|
// We've completed the first future -- remove it and start on
|
|
// the second!
|
|
Poll::Ready(()) => self.first.take(),
|
|
// We couldn't yet complete the first future.
|
|
Poll::Pending => return Poll::Pending,
|
|
};
|
|
}
|
|
// Now that the first future is done, attempt to complete the second.
|
|
self.second.poll(wake)
|
|
}
|
|
}
|
|
// ANCHOR_END: and_then
|
|
|
|
mod real_future {
|
|
use std::{
|
|
future::Future as RealFuture,
|
|
pin::Pin,
|
|
task::{Context, Poll},
|
|
};
|
|
|
|
// ANCHOR: real_future
|
|
trait Future {
|
|
type Output;
|
|
fn poll(
|
|
// Note the change from `&mut self` to `Pin<&mut Self>`:
|
|
self: Pin<&mut Self>,
|
|
// and the change from `wake: fn()` to `cx: &mut Context<'_>`:
|
|
cx: &mut Context<'_>,
|
|
) -> Poll<Self::Output>;
|
|
}
|
|
// ANCHOR_END: real_future
|
|
|
|
// ensure that `Future` matches `RealFuture`:
|
|
impl<O> Future for dyn RealFuture<Output = O> {
|
|
type Output = O;
|
|
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
|
RealFuture::poll(self, cx)
|
|
}
|
|
}
|
|
}
|