Inside an async function, .await waits for another future and then continues with its returned value.

Program

Play the program to choose a count and watch one async function await another before formatting the label.

await_chain.rs
use std::future::Future;
use std::pin::pin;
use std::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};

fn main() {
    let count = ;
    let future = build_label("task", count);
    let label = block_on(future);
    println!("{label}");
}

async fn build_label(prefix: &str, count: i32) -> String {
    let label = make_label(prefix).await;
    format!("{label}:{count}")
}

async fn make_label(prefix: &str) -> String {
    format!("{prefix}-ready")
}

fn block_on<F: Future>(future: F) -> F::Output {
    let waker = noop_waker();
    let mut context = Context::from_waker(&waker);
    let mut future = pin!(future);
    loop {
        match future.as_mut().poll(&mut context) {
            Poll::Ready(value) => return value,
            Poll::Pending => {}
        }
    }
}

fn noop_waker() -> Waker {
    unsafe { Waker::from_raw(noop_raw_waker()) }
}

fn noop_raw_waker() -> RawWaker {
    RawWaker::new(std::ptr::null(), &VTABLE)
}

static VTABLE: RawWakerVTable = RawWakerVTable::new(|_| noop_raw_waker(), |_| {}, |_| {}, |_| {});
use std::future::Future;
use std::pin::pin;
use std::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};

fn main() {
    let count = ;
    let future = build_label("task", count);
    let label = block_on(future);
    println!("{label}");
}

async fn build_label(prefix: &str, count: i32) -> String {
    let label = make_label(prefix).await;
    format!("{label}:{count}")
}

async fn make_label(prefix: &str) -> String {
    format!("{prefix}-ready")
}

fn block_on<F: Future>(future: F) -> F::Output {
    let waker = noop_waker();
    let mut context = Context::from_waker(&waker);
    let mut future = pin!(future);
    loop {
        match future.as_mut().poll(&mut context) {
            Poll::Ready(value) => return value,
            Poll::Pending => {}
        }
    }
}

fn noop_waker() -> Waker {
    unsafe { Waker::from_raw(noop_raw_waker()) }
}

fn noop_raw_waker() -> RawWaker {
    RawWaker::new(std::ptr::null(), &VTABLE)
}

static VTABLE: RawWakerVTable = RawWakerVTable::new(|_| noop_raw_waker(), |_| {}, |_| {}, |_| {});
use std::future::Future;
use std::pin::pin;
use std::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};

fn main() {
    let count = ;
    let future = build_label("task", count);
    let label = block_on(future);
    println!("{label}");
}

async fn build_label(prefix: &str, count: i32) -> String {
    let label = make_label(prefix).await;
    format!("{label}:{count}")
}

async fn make_label(prefix: &str) -> String {
    format!("{prefix}-ready")
}

fn block_on<F: Future>(future: F) -> F::Output {
    let waker = noop_waker();
    let mut context = Context::from_waker(&waker);
    let mut future = pin!(future);
    loop {
        match future.as_mut().poll(&mut context) {
            Poll::Ready(value) => return value,
            Poll::Pending => {}
        }
    }
}

fn noop_waker() -> Waker {
    unsafe { Waker::from_raw(noop_raw_waker()) }
}

fn noop_raw_waker() -> RawWaker {
    RawWaker::new(std::ptr::null(), &VTABLE)
}

static VTABLE: RawWakerVTable = RawWakerVTable::new(|_| noop_raw_waker(), |_| {}, |_| {}, |_| {});
.await `.await` pauses the surrounding async function until the awaited future is ready.
continuation After `make_label(prefix).await`, `build_label` continues with the returned string.
composition Async functions can be composed by awaiting one future inside another.