In this lesson, you will learn how to architect a minimal block_on executor to understand how an executor drives a Future to completion.
The Role of the Executor
While a Future represents a piece of work that can be done, it is inherently lazy. It holds no inherent power to poll itself. The executor’s role is to act as the "engine" that provides the necessary context and polling mechanism to transform that potential into execution.
An executor essentially manages a loop: it checks if the future is ready, and if it isn’t, it waits for the Waker to signal that progress is possible.
Architecting a block_on Executor
To implement a minimal block_on function, we need to bridge the gap between our code and the Future trait. We need three components: a Waker (to tell the executor when to try again), a Context (which holds the waker), and the polling loop.
use std::future::Future;
use std::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};
fn block_on<F: Future>(mut future: F) -> F::Output {
// 1. Create a "dummy" waker that does nothing
let waker = unsafe { Waker::from_raw(dummy_raw_waker()) };
let mut context = Context::from_waker(&waker);
// 2. Drive the future to completion
loop {
// Pinning is required here in a production environment
match unsafe { std::pin::Pin::new_unchecked(&mut future).poll(&mut context) } {
Poll::Ready(val) => return val,
Poll::Pending => {
// In a real system, we would park the thread here
// until the waker is triggered.
}
}
}
}
Why this matters
In this loop, poll is the critical handshake. If the future returns Poll::Pending, it means it has registered its Waker somewhere in the system (like an I/O reactor). The executor is then free to stop polling and wait. Once an event occurs, the Waker is signaled, which nudges the executor to re-enter the loop and call poll again.
Without the executor’s orchestration, the Future would remain an inert state machine, unable to react to the external signals required to progress.
Key Takeaway: The executor is the mechanical driver that repeatedly polls a Future until it returns Ready, transforming asynchronous intent into concrete results.