Understanding async/await and Futures in Rust.


Key Concepts

async fn Returns a Future

async fn fetch_data() -> Result<Data, Error>
// Is actually:
fn fetch_data() -> impl Future<Output = Result<Data, Error>>

The function doesn't run immediately—it returns a Future that must be .awaited or spawned.

.await Yields Control

self.client
    .get(&url)      // Build request (sync, instant)
    .send()         // Returns Future<Output = Result<Response, Error>>
    .await?         // Yield until response arrives, then ? unwraps
    .json::<T>()    // Returns another Future for body parsing
    .await          // Yield until body is fully read & deserialized

What happens at .await:

  1. Yields control back to the async runtime (tokio)
  2. Runtime can run other tasks while waiting for I/O
  3. When I/O completes, runtime resumes this function at that exact point

Two Await Points Example

pub async fn fetch_exchange_info(&self) -> Result<ExchangeInfo, reqwest::Error> {
    let url = self.config.future.market_data.exchange_info_url();

    self.client
        .get(&url)
        .send()              // Await #1: wait for HTTP response headers
        .await?
        .json::<ExchangeInfo>()  // Await #2: wait for body + deserialize
        .await
}

Result<T, E> vs Future

Concept What It Represents Async?
Result<T, E> Success (Ok(T)) or failure (Err(E)) No
Future<Output=T> A value that will exist later Yes

Result is just error handling—nothing to do with async. You can use it anywhere.

They Combine

let data = fetch().await?;
//         ^^^^^  ^^^^^ ^
//         Future gets  unwraps
//                Result Result