liveBook · Manning

Ready

As explained in Rust Servers, Services, and Apps

Poll::Ready is a Rust polling result indicating that an asynchronous computation has produced its output.

Poll::Ready(value) reports that an asynchronous computation has finished and produced its output. An executor receives it when polling a Future. section 10.6

A polling cycle uses Poll::Ready alongside deferred completion:

  • Return Poll::Ready with the timer’s String after the expiration time is reached. section 10.5
  • Return Poll::Pending before completion, allowing the executor to schedule other tasks. section 10.5
  • Resume polling after a Waker informs the async executor that progress may continue. section 10.6

Completing a custom timer

An AsyncTimer checks Instant::now() against its expiration time. Once the deadline arrives, poll returns Poll::Ready(String::from("Future 1 has completed")); otherwise it arranges a wake-up and returns Poll::Pending. section 10.5

use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};
use std::thread::sleep;
use std::time::{Duration, Instant};
 
struct AsyncTimer {                                            #1
    expiration_time: Instant,
}
 
impl Future for AsyncTimer {                                   #2
    type Output = String;                                      #3
 
    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) ->
      Poll<Self::Output> {                                     #4
        if Instant::now() >= self.expiration_time {            #5
            println!("Hello, it's time for Future 1");
            Poll::Ready(String::from("Future 1 has completed"))
        } else {
          println!("Hello, it's not yet time for Future 1. Going to sleep");
          let waker = cx.waker().clone();
          let expiration_time = self.expiration_time;
          std::thread::spawn(move || {                         #6
              let current_time = Instant::now();
              if current_time < expiration_time {
                  std::thread::sleep(expiration_time - current_time);
              }
              waker.wake();                                    #7
          });
          Poll::Pending
      }
    }
}
 
#[tokio::main]
async fn main() {
    let h1 = tokio::spawn(async {
        let future1 = AsyncTimer {                             #8
            expiration_time: Instant::now() + Duration::from_millis(4–––),
        };
        println!("{:?}", future1.await);
    });
 
    let h2 = tokio::spawn(async {
        let file2_contents = read_from_file2().await;
        println!("{:?}", file2_contents);
    });
    let _ = tokio::join!(h1, h2);
}
 
// function that simulates reading from a file
fn read_from_file2() -> impl Future<Output = String> {
    async {
        sleep(Duration::new(2, –));
        String::from("Future 2 has completed")
    }
}

The implementation listing shows Poll::Ready in a Future implementation, alongside the timer state and poll signature. section 10.5

How Rust Servers, Services, and Apps covers it

How deep it goes
Explains the result variant through executor behavior and a custom timer, while deferring broader runtime implementation details.
Examples
Uses an expiration timer and a file-reading future to demonstrate completion output and interleaved task execution.
What it assumes
Builds on Future polling, async executors, Poll::Pending, and Waker-based task notification.
What you can do after
Build it from scratch by returning Poll::Ready from a custom Future when its computation has produced a value.
How it connects
Connects Future, Poll::Pending, Waker, async runtime, and Tokio through task polling and rescheduling.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Rust Servers, Services, and Apps. The section links point to the parts of the book it draws on.