This is a tutorial dedicated to helping you learn asynchronous programming via Futures library through simple step by step examples.

What is Futures?

It is a Rust library that allows you achieve a Zero-cost asynchronous programming in Rust.

futures-rs is a library providing the foundations for asynchronous programming in Rust. It includes key trait definitions like Stream, as well as utilities like join!, select!, and various futures combinator methods which enable expressive asynchronous control flow.

Installation

To install it declare it in the Cargo.toml:

[dependencies]
futures = "0.3"

Use

Then use it. Start by importing:

use futures::future::Future;

Let’s look at some examples.

Example 1: Rust Futures Example

A simple rust futures-rs example.

Step 1: Install it

Install it as has been described.

Step 2: Write Code

Here’s an imperative example:

use futures::channel::mpsc;
use futures::executor; //standard executors to provide a context for futures and streams
use futures::executor::ThreadPool;
use futures::StreamExt;

fn main() {
    let pool = ThreadPool::new().expect("Failed to build pool");
    let (tx, mut rx) = mpsc::unbounded::<i32>();

    // Create a future by an async block, where async is responsible for generating
    // an implementation of Future. At this point no executor has been provided
    // to this future, so it will not be running.
    let fut_values = async {
        // Create another async block, again where Future is implemented by
        // async. Since this is inside of a parent async block, it will be
        // provided with the executor of the parent block when the parent
        // block is executed.
        //
        // This executor chaining is done by Future::poll whose second argument
        // is a std::task::Context. This represents our executor, and the Future
        // implemented by this async block can be polled using the parent async
        // block's executor.
        let fut_tx_result = async move {
            (0..100).for_each(|v| {
                tx.unbounded_send(v).expect("Failed to send");
            })
        };

        // Use the provided thread pool to spawn the transmission
        pool.spawn_ok(fut_tx_result);

        let mut pending = vec![];
        // Use the provided executor to wait for the next value
        // of the stream to be available.
        while let Some(v) = rx.next().await {
            pending.push(v * 2);
        }

        pending
    };

    // Actually execute the above future, which will invoke Future::poll and
    // subsequently chain appropriate Future::poll and methods needing executors
    // to drive all futures. Eventually fut_values will be driven to completion.
    let values: Vec<i32> = executor::block_on(fut_values);

    println!("Values={:?}", values);
}

Reference

Read more here.

Categorized in: