Future trait
- Rust course
- Advanced
- Lesson 3/81
- 4 min
Learn the Future trait's poll mechanism.
The Future trait
Behind async fn there is a trait with a single method:
pub trait Future {
type Output;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>;
}
pub enum Poll<T> {
Ready(T),
Pending,
}poll either returns the result (Ready) or says it isn't ready yet (Pending). A future returning Pending promises to wake the executor via cx.waker() when it's ready.
A hand-written future
A future that returns Pending a few times and then becomes ready:
struct Geri {
kalan: u32,
}
impl Future for Geri {
type Output = &'static str;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
if self.kalan == 0 {
return Poll::Ready("bitti");
}
self.kalan -= 1;
cx.waker().wake_by_ref(); // "poll me again"
Poll::Pending
}
}Since Geri's fields are Unpin, the fields can be accessed directly through Pin<&mut Self>.
Practice Counting executor
Write the Geri future above. Change block_on into calistir, which returns the result together with how many times it polled. Print both for Geri { kalan: 3 }, separated by a space.
Starter code
use std::future::Future;
use std::pin::{pin, Pin};
use std::task::{Context, Poll, Waker};
fn main() {
// buraya yaz
}Sample solution
use std::future::Future;
use std::pin::{pin, Pin};
use std::task::{Context, Poll, Waker};
struct Geri {
kalan: u32,
}
impl Future for Geri {
type Output = &'static str;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
if self.kalan == 0 {
return Poll::Ready("bitti");
}
self.kalan -= 1;
cx.waker().wake_by_ref();
Poll::Pending
}
}
fn calistir<F: Future>(f: F) -> (F::Output, u32) {
let mut f = pin!(f);
let mut cx = Context::from_waker(Waker::noop());
let mut sayi = 0;
loop {
sayi += 1;
if let Poll::Ready(v) = f.as_mut().poll(&mut cx) {
return (v, sayi);
}
}
}
fn main() {
let (sonuc, n) = calistir(Geri { kalan: 3 });
println!("{} {}", sonuc, n);
}Expected output
bitti 4
Questions and answers
Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.
1 What happens in a real runtime if a future returns <code>Pending</code> and never calls the Waker?
- The runtime retries
- Panic
- The result becomes None
- The task is never polled again and hangs forever Correct answer
Explanation: The wake-up contract is mandatory; it's the most common mistake when writing your own future.
2 Not ready yet
self.kalan -= 1;
cx.waker().wake_by_ref();
Poll::____
self.kalan -= 1;
cx.waker().wake_by_ref();
Poll::Pending
Explanation: Pending reports that the result isn't ready yet.
3 Item and role
| Term | Meaning |
|---|---|
Poll::Ready(v) |
Result ready |
Poll::Pending |
Later |
cx.waker() |
Waker |
type Output |
Result type |