[Stabilization] Future APIs · Issue #59725 · rust-lang/rust (original) (raw)
Feature name: futures_api
Stabilization target: 1.36.0
Tracking issue: #59113
Related RFCs:
- RFC: stabilize std::task and std::future::Future rfcs#2592 Futures API
- async/await notation for ergonomic asynchronous IO rfcs#2394 async/await
- (closed) RFC: add futures to libcore rfcs#2395 Futures API
- (closed) RFC: add futures and task system to libcore rfcs#2418 Futures API
I propose that we stabilize the futures_api
feature, making the Future trait available on stable Rust. This is an important step in stabilizing the async/await feature and providing a stable, ergonomic, zero-cost abstraction for async IO in Rust.
The futures API was first introduced as a part of the std library prior to 1.0. It was removed from std shortly after 1.0, and was developed outside of std in an external crate called futures, first released in 2016. Since that time, the API has undergone significant evolution.
All the APIs being stabilized are exposed through both core and std.
The future
Module
We shall stabilize these items in the future module:
- The
std::future
module itself - The
std::future::Future
trait and both of its associated items (Output
andpoll
)
We do not stabilize the other items in this module, which are implementation details of async/await as it currently exists that are not intended to be stabilized.
The task
Module
We shall stabilize these items in the task module:
- The
std::task
module itself - The
std::task::Poll
enum - The
std::task::Waker
struct and all three of its methods (wake, wake_by_ref, will_wake, and new_unchecked). new_unchecked shall be renamed to from_raw. - The
std::task::RawWaker
type and its methodnew
- The
std::task::RawWakerVTable
type and its methodnew
(see Unexpected panic when going from debug to release build #59919) - The
std::task::Context
type and its methodsfrom_waker
andwaker
Notice: Late Changes to the API
We have decided to merge the future-proofing changes proposed in #59119 to leave room for some potential extensions to the API after stabilization. See further discussion on that issue.
Notes on Futures
The poll-based model
Unlike other languages, the Future API in Rust uses a poll based execution model. This follows a back and forth cycle involving an executor (which is responsible for executing futures) and a reactor (which is responsible for managing IO events):
- Poll: The executor polls a spawned future until it returns. It passes in a waker; waking that waker will cause the executor to poll this future again. If the future encounters IO, it gives the waker to the reactor and returns pending.
- Wake: Once there is more progress to be made by polling the future, the reactor calls the wake method on the waker it has registered. This causes the future to be polled again by the executor, continuing the cycle.
Eventually, the future returns ready instead of pending, indicating that the future has completed.
Pinning
The Future trait takes self by Pin<&mut Self>
. This is based on the pinning APIs stabilized in 1.33. This contract allows implementers to assume that once a future is being polled, it will not be moved again. The primary benefit of this is that async items can have borrows across await points, desugared into self-referential fields of the anonymous future type.
Changes proposed in this stabilization report
Waker::new_unchecked
is renamed toWaker::from_raw
std has unsafe constructors following both names, from_raw is more specific than new_unchecked (its a constructor taking the "raw" type which is possibly invalid, asserting that this instance is valid).
Waker::wake
takes self by value and newWaker::wake_by_ref
takes self by reference
The most common waker implementation is to be an arc of the task which re-enqueues itself when the waker is woken; to implement this by reference, you must clone the arc and put it on the queue. But most uses of wake drop the waker as soon as they call wake. This results in an unnecessary atomic reference increment and decrement; instead we now provide by a by-value and by-reference implementation, so users can use the form most optimal for their situation.
Moderation note
The futures APIs have been discussed at enormous length over the past 3 years. Every aspect of the API has been debated, reviewed and considered by the relevant teams and the Rust community as a whole. When posting to this thread, please make a good faith effort to review the history and see if your concern or proposal has been posted before, and how and why it was resolved.