Skip to content

[Stabilization] Future APIs #59725

Closed
Closed

Description

Feature name: futures_api
Stabilization target: 1.36.0
Tracking issue: #59113
Related RFCs:

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 and poll)

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 method new
  • The std::task::RawWakerVTable type and its method new (see Unexpected panic when going from debug to release build #59919)
  • The std::task::Context type and its methods from_waker and waker

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 to Waker::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 new Waker::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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

No one assigned

    Labels

    T-langRelevant to the language team, which will review and decide on the PR/issue.T-libs-apiRelevant to the library API team, which will review and decide on the PR/issue.disposition-mergeThis issue / PR is in PFCP or FCP with a disposition to merge it.finished-final-comment-periodThe final comment period is finished for this PR / Issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions