Chapter 19: More crates and async Rust
The introduction previews reqwest and async Rust and explains why feature flags can help reduce compilation time.
After this chapter you will be able to
- Feature flags and compilation time. Explain that feature flags let a project bring in only part of an external crate, which can help keep compilation time down.
- GET request construction. Trace how the section builds a simple GET request: create a reqwest Client, pass a URL to .get(), and call .send() on the resulting RequestBuilder.
- Async and blocking clients. Explain why the first .send() attempt points toward async Rust and why the section tries reqwest::blocking::Client instead.
- Selective crate compilation. Explain why crates use feature flags and why a feature available in the Playground may need to be enabled in a local project.
- Finding and enabling blocking. Describe how to check whether missing reqwest functionality is behind a feature flag and enable its blocking Client.
- Nonblocking waits in async Rust. Explain how async Rust differs from regular blocking code when an operation takes time, using a slow reqwest request as an example.
- Future readiness and output. Explain that a Future represents a value that may become available later, and distinguish its Ready and Pending states. Describe Output as the associated type of that value and poll as the method for checking readiness.
- Async function return type. Distinguish an ordinary function returning a u8 immediately from an async fn written with the same return type. Explain that the async function actually returns an impl Future<Output = u8>, which may finish later while other work can be done.
- Future polling outcomes. Explain what polling a Future checks and distinguish `Poll::Pending` from `Poll::Ready(val)`.
- Await inside async code. Describe how `.await` is used to obtain a Future’s output and where Rust permits it.
- Need for an async run time. Explain why changing `main` to `async fn` is not enough and what an async run time takes care of.
- Tokio async main runtime. Explain how `#[tokio::main]` lets a program use an async main function without manually polling it.
- Await context and function calls. Describe where `.await` can be used and how calling async functions affects other functions in the program.
- Sequential awaits and join. Explain why awaiting each future before starting the next differs from using join! to poll multiple futures at the same time. Describe why the joined example can print completion messages in different orders while its resulting numbers remain (1, 2, 3).
- First completion with select. Describe how select! polls several futures and acts on the first one that finishes, including the example’s timeout branch. Explain how its named-future and => branch syntax can make outputs of different types compatible.
What it builds on
- Crates and Cargo.toml (chapter 16) · Introduces external crates.
- impl Trait (chapter 12) · The impl Trait syntax used to describe the hidden return type.
- The ? operator (chapter 6) · Using the `?` operator for error handling.
Section by section
Introduction
The introduction previews reqwest and async Rust and explains why feature flags can help reduce compilation time.
- Feature flags and compilation time: Explain that feature flags let a project bring in only part of an external crate, which can help keep compilation time down.
Why it matters: This gives you the reason to consider feature flags when using an external crate.
Key terms: feature flags, external crate, compilation time
19.1 The reqwest crate
Introduces making a GET request with reqwest and shows why its default Client leads to an async return type, prompting a look at the blocking Client.
- GET request construction: Trace how the section builds a simple GET request: create a reqwest Client, pass a URL to .get(), and call .send() on the resulting RequestBuilder.
Why it matters: This is the basic request-building sequence used in the section’s example. - Async and blocking clients: Explain why the first .send() attempt points toward async Rust and why the section tries reqwest::blocking::Client instead.
Why it matters: It explains the choice of client in the example without requiring the async details taught later.
Key terms: Client, .get(), IntoUrl, RequestBuilder, .send(), Future, async Rust, blocking Client, reqwest::blocking::Client
19.2 Feature flags
This section explains why crates use feature flags, how to enable reqwest’s blocking feature, and what its response provides.
- Selective crate compilation: Explain why crates use feature flags and why a feature available in the Playground may need to be enabled in a local project.
Why it matters: Selecting only the features you need can avoid compiling unused code. - Finding and enabling blocking: Describe how to check whether missing reqwest functionality is behind a feature flag and enable its blocking Client.
Why it matters: A missing item may be disabled rather than absent from the crate altogether. - Blocking response text: Trace what the section does with the response after enabling reqwest’s blocking Client.
Why it matters: It connects enabling the feature to the request result the example prints.
Key terms: feature flags, Cargo.toml, Playground, blocking, cargo add reqwest --feature blocking, #[cfg(feature = "feature_name")], Response, .get(), .text(), Result<String>
19.3 Async Rust
Introduces async Rust as a way to keep other work moving while code waits for a slow operation, such as a server response.
- Nonblocking waits in async Rust: Explain how async Rust differs from regular blocking code when an operation takes time, using a slow reqwest request as an example.
Why it matters: Waiting for a server need not leave other work idle.
Key terms: async Rust, block, thread, reqwest crate
19.3.1 Async basics
This section introduces a Future as a value that may become available later and explains what an async function actually returns.
- Future readiness and output: Explain that a Future represents a value that may become available later, and distinguish its Ready and Pending states. Describe Output as the associated type of that value and poll as the method for checking readiness.
Why it matters: This distinction explains why an async result might not be available immediately. - Async function return type: Distinguish an ordinary function returning a u8 immediately from an async fn written with the same return type. Explain that the async function actually returns an impl Future<Output = u8>, which may finish later while other work can be done.
Why it matters: It prevents you from treating an async function’s return value as though its result were already available.
Key terms: Future, Ready, Pending, Output, poll, async fn, fn, impl Future<Output = u8>
19.3.2 Checking whether a Future is ready
This section explains how polling checks a Future, why `.await` needs an async context, and why an async run time is needed to run async code.
- Future polling outcomes: Explain what polling a Future checks and distinguish `Poll::Pending` from `Poll::Ready(val)`.
Why it matters: These two outcomes explain why an async operation may produce a value now or need another check later. - Await inside async code: Describe how `.await` is used to obtain a Future’s output and where Rust permits it.
Why it matters: This explains both the purpose of `.await` and why adding it to an ordinary `main` fails. - Need for an async run time: Explain why changing `main` to `async fn` is not enough and what an async run time takes care of.
Why it matters: The run time supplies the missing piece between writing an async function and actually running its Future.
Key terms: poll, Future, Poll::Pending, Poll::Ready(val), .await, async, polling, async fn main, async run time, Tokio
19.3.3 Using an async run time
This section shows how Tokio runs an async main function and how to use `.await` when calling async functions, including reqwest calls.
- Tokio async main runtime: Explain how `#[tokio::main]` lets a program use an async main function without manually polling it.
Why it matters: It explains why adding Tokio’s attribute makes the async program run to completion. - Await context and function calls: Describe where `.await` can be used and how calling async functions affects other functions in the program.
Why it matters: These rules help explain both where to put `.await` and why async can spread through calling functions. - Awaiting async reqwest calls: Describe how the section applies `.await` to async reqwest calls and why `.await?` commonly appears in async code.
Why it matters: The reqwest example connects the async rules to a common pattern in real code.
Key terms: Tokio, #[tokio::main], async fn main(), run time, .await, async fn, async block, regular functions, reqwest, Client
19.3.4 Some other details about async Rust
This section compares awaiting futures one by one with polling them together, then introduces macros for taking the first result or handling failures and notes where async Rust tools live.
- Sequential awaits and join: Explain why awaiting each future before starting the next differs from using join! to poll multiple futures at the same time. Describe why the joined example can print completion messages in different orders while its resulting numbers remain (1, 2, 3).
Why it matters: It shows why code that uses async and .await may still miss the benefit of polling independent futures together. - First completion with select: Describe how select! polls several futures and acts on the first one that finishes, including the example’s timeout branch. Explain how its named-future and => branch syntax can make outputs of different types compatible.
Why it matters: It gives you a way to respond to whichever of several async operations finishes first. - Failure handling with try_join: Distinguish try_join! from ordinary joining by stating what happens when one of its futures fails.
Why it matters: It identifies the joining option this section gives for futures that can fail. - External async ecosystem: Explain why readers will encounter async tools in external crates as well as the standard library, using async traits as the section’s example of a feature that became available in Rust itself.
Why it matters: It helps explain why async Rust examples and existing code may depend on crates even as Rust gains related capabilities.
Key terms: .await, join!, poll, future, select!, =>, timeout, try_join!, Err, external crates
19.4 Summary
Where this is used later
- Setup and first code (chapter 23) · Prior use of the reqwest crate.
Concepts explained in this chapter
- async/awaitasync is a Rust language construct for defining computations that produce futures and can suspend while awaiting asynchronous results.
- futureA Future is a Rust abstraction representing an asynchronous computation whose result may become available later and which can be polled for readiness.
- feature flagA feature flag is a configuration option that conditionally enables code, dependencies, or capabilities during compilation.
- pollpoll is the operation by which an asynchronous runtime advances a future toward completion and obtains its current state or output.
- select macroThe select! macro concurrently polls multiple futures and executes the branch corresponding to the first future that completes.
- reqwest::ClientA reqwest Client is an HTTP client handle that executes requests and manages client-side request configuration and resources.
- join!join! is an asynchronous macro that concurrently drives multiple futures and completes when all of them complete.
- pollingPolling is the process of repeatedly checking asynchronous computations for progress or completion.
- try_join macroThe try_join! macro concurrently joins futures and returns an error as soon as one of them fails.
- TokioTokio is a Rust asynchronous runtime and library for scheduling tasks, polling futures, and performing asynchronous I/O.
- async runtimeAn async runtime is software that schedules asynchronous tasks, drives Future polling, and determines when suspended computations are polled again.
- reqwestreqwest is a Rust library for making HTTP requests, including through asynchronous clients.
- HTTP GETHTTP GET is a request method for retrieving a resource or representation from a server.
- associated typeAn associated type is a type declaration attached to a Rust trait whose concrete value is specified for each implementation.
- functionA function is a named unit of executable code that can accept inputs and produce a result.
- question mark operatorThe question mark operator is Rust syntax that propagates an error from a Result or absence from an Option.
These guides are generated from the text of Manning books by Manning's knowledge graph and link to the sections they draw on. The full books are available on liveBook and at manning.com.
