In this lesson, you will learn how the Rust compiler transforms high-level async blocks into low-level state machines that track execution progress.
The Hidden Transformation
When you write an async function, the compiler doesn't just "run" it. Instead, it generates an anonymous struct that implements the Future trait. This struct acts as a state machine, where each .await point represents a transition between states.
Consider this simple function:
async fn example(a: i32) -> i32 {
let b = 10;
let res = some_other_async(a).await;
res + b
}
The Desugared State Machine
Under the hood, the compiler rewrites this into a structure roughly equivalent to this:
enum ExampleFuture {
Initial { a: i32 },
Waiting { b: i32, sub_future: SomeOtherFuture },
Done,
}
When you first call example, it returns ExampleFuture::Initial. The first time the executor calls poll on this future, it initializes b and triggers some_other_async. The future then transitions to the Waiting state, storing the sub_future and the local variable b inside the variant.
Crucially, the compiler performs capture analysis. Any variable you define that is live across an .await point (like b in our example) is moved into the state machine's struct. If you held a MutexGuard across an .await, the compiler would store that guard in the Waiting variant, which is precisely why the compiler forces you to handle Send and Sync constraints—it is effectively serializing your stack frame into heap-allocated data.
Why It Matters
When the executor polls the future again, it looks at the current variant. It doesn't restart the function from the top; it jumps directly to the state saved in the Waiting variant, checks if sub_future has completed, and resumes execution exactly where it left off. This state machine is why async functions are "lazy": nothing happens until the executor polls this generated struct, and the state is preserved across yield points without blocking a physical thread.
Key Takeaway: The async keyword is syntactic sugar that compiles your function into an enum-based state machine, storing local variables as fields in an auto-generated struct to persist them across yield points.