Macro tokio::pin

source · []
macro_rules! pin {
    ($($x:ident),*) => { ... };
    ($(
            let $x:ident = $init:expr;
    )*) => { ... };
}
Expand description

Pins a value on the stack.

Calls to async fn return anonymous Future values that are !Unpin. These values must be pinned before they can be polled. Calling .await will handle this, but consumes the future. If it is required to call .await on a &mut _ reference, the caller is responsible for pinning the future.

Pinning may be done by allocating with Box::pin or by using the stack with the pin! macro.

The following will fail to compile:

async fn my_async_fn() {
    // async logic here
}

#[tokio::main]
async fn main() {
    let mut future = my_async_fn();
    (&mut future).await;
}

To make this work requires pinning:

use tokio::pin;

async fn my_async_fn() {
    // async logic here
}

#[tokio::main]
async fn main() {
    let future = my_async_fn();
    pin!(future);

    (&mut future).await;
}

Pinning is useful when using select! and stream operators that require T: Stream + Unpin.

Usage

The pin! macro takes identifiers as arguments. It does not work with expressions.

The following does not compile as an expression is passed to pin!.

async fn my_async_fn() {
    // async logic here
}

#[tokio::main]
async fn main() {
    let mut future = pin!(my_async_fn());
    (&mut future).await;
}

Examples

Using with select:

use tokio::{pin, select};
use tokio_stream::{self as stream, StreamExt};

async fn my_async_fn() {
    // async logic here
}

#[tokio::main]
async fn main() {
    let mut stream = stream::iter(vec![1, 2, 3, 4]);

    let future = my_async_fn();
    pin!(future);

    loop {
        select! {
            _ = &mut future => {
                // Stop looping `future` will be polled after completion
                break;
            }
            Some(val) = stream.next() => {
                println!("got value = {}", val);
            }
        }
    }
}

Because assigning to a variable followed by pinning is common, there is also a variant of the macro that supports doing both in one go.

use tokio::{pin, select};

async fn my_async_fn() {
    // async logic here
}

#[tokio::main]
async fn main() {
    pin! {
        let future1 = my_async_fn();
        let future2 = my_async_fn();
    }

    select! {
        _ = &mut future1 => {}
        _ = &mut future2 => {}
    }
}