Asynchronous Programming in Rust › Composing futures concurrently › Join › Alternatives

Futures-concurrency also provides functionality for join (and try_join). In the futures-concurrency style, these operations are trait methods on groups of futures such as tuples, `Vec`s, or arrays. E.g., to join two futures, you would write `(fut1, fut2).join().await` (note that `await` is explicit here).
If the set of futures you wish to join together varies dynamically (e.g., new futures are created as input comes in over the network), or you want the results as they complete rather than when all the futures have completed, then you'll need to use streams and the `FuturesUnordered` or `FuturesOrdered` functionality. We'll cover these in the streams chapter.
[^into]: The expressions must have a type which implements `IntoFuture`. The expression is evaluated and converted to a future by the macro. I.e., they don't actually have to evaluate to a future, but rather something which can be converted into a future, but this is a pretty minor distinction. The expressions themselves are evaluated sequentially before any of the resulting futures are executed.


Asynchronous Programming in Rust › Composing futures concurrently › Race/select

The counterpart to joining futures is racing them (aka selecting on them). With race/select the futures are executed concurrently, but rather than waiting for all the futures to complete, we only wait for the first one to complete and then cancel the others. Although this sounds similar to joining, it is significantly more interesting (and sometimes error-prone) because now we have to reason about cancellation.
Here's an example using Tokio's `select` macro:
```rust,norun
async fn main() {
  select! {
    result = do_a_thing() => {
      println!("computation completed and returned {result}");
    }
    _ = timeout() => {
      println!("computation timed-out");
    }
  }
}
```
You'll notice things are already more interesting than with the `join` macro because we handle the results of the futures within the `select` macro. It looks a bit like a `match` expression, but with `select`, all branches are run concurrently and the body of the branch which finishes first is executed with its result (the other branches are not executed and the futures are cancelled by `drop`ping). In the example, `do_a_thing` and `timeout` execute concurrently and the first to complete will have it's block executed (i.e., only one `println` will run), the other future will be cancelled. As with the `join` macro, awaiting the futures is implicit.
Tokio's `select` macro supports a bunch of features:

Composing futures concurrently
Race/select


Asynchronous Programming in Rust › Composing futures concurrently › Race/select

- pattern matching: the syntax on the left of `=` on each branch can be a pattern and the block is only executed if the result of the future matches the pattern. If the pattern does not match, then the future is no longer polled (but other futures are). This can be useful for futures which optionally return a value, e.g., `Some(x) = do_a_thing() => { ... }`.
- `if` guards: each branch may have an `if` guard. When the `select` macro runs, after evaluating each expression to produce a future, the `if` guard is evaluated and the future is only polled if the guard is true. E.g., `x = = do_a_thing() if false => { ... }` will never be polled. Note that the `if` guard is not re-evaluated during polling, only when the macro is initialized.
- `else` branch: `select` can have an `else` branch `else => { ... }`, this is executed if all the futures have stopped and none of the blocks have been executed. If this happens without an `else` branch, then `select` will panic.
The value of the `select!` macro is the value of the executed branch (just like `match`), so all branches must have the same type. E.g., if we wanted to use the result of the above example outside of the `select`, we'd write it like
```rust,norun
async fn main() {
  let result = select! {
    result = do_a_thing() => {
      Some(result)
    }
    _ = timeout() => {
      None
    }
  };

  // Use `result`
}
```


Asynchronous Programming in Rust › Composing futures concurrently › Race/select

As with `join!`, `select!` does not treat `Result`s in any special way (other than the pattern matching mentioned previously) and if a branch completes with an error, then all other branches will be cancelled and the error will be used as the result of select (in the same way as if the branch has completed successfully).
The `select` macro intrinsically uses cancellation, so if you're trying to avoid cancellation in your program, you must avoid `select!`. In fact, `select` is often the primary source of cancellation in an async program. As discussed elsewhere, cancellation has many subtle issues which can lead to bugs. In particular, note that `select` cancels futures by simply dropping them. This will not notify the future being dropped or trigger any cancellation tokens, etc.
`select!` is often used in a loop to handle streams or other sequences of futures. This adds an extra layer of complexity and opportunities for bugs. In the simple case that we create a new, independent future on each iteration of the loop, things are not much more complicated. However, this is rarely what is needed. Generally we want to preserve some state between iterations. It is common to use `select` in a loop with streams, where each iteration of the loop handles one result from the stream. E.g.:
```rust,norun
async fn main() {
  let mut stream = ...;

  loop {
    select! {
      result = stream.next() => {
        match result {
          Some(x) => println!("received: {x}"),
          None => break,
        }
      }
      _ = timeout() => {
        println!("time out!");
        break;
      }
    }
  }
}
```


Asynchronous Programming in Rust › Composing futures concurrently › Race/select

In this example, we read values from `stream` and print them until there are none left or waiting for a result times out. What happens to any remaining data in the stream in the timeout case depends on the implementation of the stream (it might be lost! Or duplicated!). This is an example of why behaviour in the face of cancellation can be important (and tricky).
We may want to reuse a future, not just a stream, across iterations. For example, we may want to race against a timeout future where the timeout applies to all iterations rather than applying a new timeout for each iteration. This is possible by creating the future outside of the loop and referencing it:
```rust,norun
async fn main() {
  let mut stream = ...;
  let mut timeout = timeout();

  loop {
    select! {
      result = stream.next() => {
        match result {
          Some(x) => println!("received: {x}"),
          None => break,
        }
      }
      // Create a reference to `timeout` rather than moving it.
      _ = &mut timeout => {
        println!("time out!");
        break;
      }
    }
  }
}
```
There are a couple of important details when using `select!` in a loop with futures or streams created outside of the `select!`. These are a fundamental consequence of how `select` works, so I'll introduce them by stepping through the details of `select`, using `timeout` in the last example as an example.
- `timeout` is created outside of the loop and initialised with some time to count down.
- On each iteration of the loop, `select` creates a reference to `timeout`, but does not change its state.
- As `select` executes, it polls `timeout` which will return `Pending` while there is time left and `Ready` when the time elapses, at which point its block is executed.


Asynchronous Programming in Rust › Composing futures concurrently › Race/select

In the above example, when `timeout` is ready, we `break` out of the loop. But what if we didn't do that? In that case, `select` would simply poll `timeout` again, which the `Future` docs say should not happen! `select` can't help this, it doesn't have any state (between iterations) to decide if `timeout` should be polled. Depending on how `timeout` is written, this might cause a panic, a logic error, or some kind of crash.
You can prevent this kind of bug in several ways:
- Use a fused future or stream so that re-polling is safe.
- Ensure that your code is structured so that futures are never re-polled, e.g., by breaking out of the loop (as in the previous example), or by using an `if` guard.


Asynchronous Programming in Rust › Composing futures concurrently › Race/select

Now, lets consider the type of `&mut timeout`. Lets assume that `timeout()` returns a type which implements `Future`, which might be an anonymous type from an async function, or it might be a named type like `Timeout`. Lets assume the latter because it makes the examples easier (but the logic applies in either case). Given that `Timeout` implents `Future`, will `&mut Timeout` implement `Future`? Not necessarily! There is a blanket `impl` which makes this true, but only if `Timeout` implements `Unpin`. That is not the case for all futures, so often you'll get a type error writing code like the last example. Such an error is easily fixed though by using the `pin` macro, e.g., `let mut timeout = pin!(timeout());`
Cancellation with `select` in a loop is a rich source of subtle bugs. These usually happen where a future contains some state involving some data but not the data itself. When the future is dropped by cancellation, that state is lost but the underlying data is not updated. This can lead to data being lost or processed multiple times.


Asynchronous Programming in Rust › Composing futures concurrently › Race/select › Alternatives

Futures.rs has its own `select` macro and futures-concurrency has a Race trait which are alternatives to Tokio's `select` macro. These both have the same core semantics of concurrently racing multiple futures, processing the result of the first and cancelling the others, but they have different syntax and vary in the details.
Futures.rs' `select` is superficially similar to Tokio's; to summarize the differences, in the futures.rs version:
- Futures must always be fused (enforced by type-checking).
- `select` has `default` and `complete` branches, rather than an `else` branch.
- `select` does not support `if` guards.
Futures-concurrency's `Race` has a very different syntax, similar to it's version of `join`, e.g., `(future_a, future_b).race().await` (it works on `Vec`s and arrays as well as tuples). The syntax is less flexible than the macros, but fits in nicely with most async code. Note that if you use `race` within a loop, you can still have the same issues as with `select`.
As with `join`, spawning tasks and letting them execute in parallel is often a good alternative to using `select`. However, cancelling the remaining tasks after the first completes requires some extra work. This can be done using channels or a cancellation token. In either case, cancellation requires some action by the task being cancelled which means the task can do some tidying up or other graceful shutdown.

Composing futures concurrently
Race/select
Alternatives


Asynchronous Programming in Rust › Composing futures concurrently › Race/select › Alternatives

A common use for `select` (especially inside a loop) is working with streams. There are stream combinator methods which can replace some uses of select. For example, `merge` in futures-concurrency is a good alternative to merge multiple streams together.


Asynchronous Programming in Rust › Composing futures concurrently › Final words

In this section we've talked about two ways to run groups of futures concurrently. Joining futures means waiting for them all to finish; selecting (aka racing) futures means waiting for the first to finish. In contrast to spawning tasks, these compositions make no use of parallelism.
Both `join` and `select` operate on sets of futures which are known in advance (often when writing the program, rather than at runtime). Sometimes, the futures to be composed are not known in advance - futures must be added to the set of composed futures as they are being executed. For this we need streams which have their own composition operations.
It's worth reiterating that although these composition operators are powerful and expressive, it is often easier and more appropriate to use tasks and spawning: parallelism is often desirable, you're less likely to have bugs around cancellation or blocking, and resource allocation is usually fairer (or at least simpler) and more predictable.

Composing futures concurrently
Final words


Asynchronous Programming in Rust › Channels, locking, and synchronization

note on runtime specificness of sync primitves
Why we need async primitives rather than use the sync ones


Asynchronous Programming in Rust › Channels, locking, and synchronization › Channels

- basically same as the std ones, but await
  - communicate between tasks (same thread or different)
- one shot
- mpsc
- other channels
- bounded and unbounded channels

Channels, locking, and synchronization
Channels


Asynchronous Programming in Rust › Channels, locking, and synchronization › Locks

- async Mutex
  - c.f., std::Mutex - can be held across await points (borrowing the mutex in the guard, guard is Send, scheduler-aware? or just because lock is async?), lock is async (will not block the thread waiting for lock to be available)
    - even a clippy lint for holding the guard across await (https://rust-lang.github.io/rust-clippy/master/index.html#await_holding_lock)
  - more expensive because it can be held across await
    - use std::Mutex if you can
      - can use try_lock or mutex is expected to not be under contention
  - lock is not magically dropped when yield (that's kind of the point of a lock!)
  - deadlock by holding mutex over await
    - tasks deadlocked, but other tasks can make progress so might not look like a deadlock in process stats/tools/OS
    - usual advice - limit scope, minimise locks, order locks, prefer alternatives
  - no mutex poisoning
  - lock_owned
  - blocking_lock
    - cannot use in async
  - applies to other locks (should the above be moved before discussion of mutex specifically? Probably yes)
- RWLock
- Semaphore
- yielding

Channels, locking, and synchronization
Locks


Asynchronous Programming in Rust › Channels, locking, and synchronization › Other synchronization primitives

- notify, barrier
- OnceCell
- atomics

Channels, locking, and synchronization
Other synchronization primitives


Asynchronous Programming in Rust › Tools for async programming

- Why we need specialist tools for async
- Are there other tools to cover
  - loom


Asynchronous Programming in Rust › Tools for async programming › Monitoring

- Tokio console


Asynchronous Programming in Rust › Tools for async programming › Tracing and logging

- issues with async tracing
- tracing crate (https://github.com/tokio-rs/tracing)

Tools for async programming
Tracing and logging


Asynchronous Programming in Rust › Tools for async programming › Debugging

- Understanding async backtraces (RUST_BACKTRACE and in a debugger)
- Techniques for debugging async code
- Using Tokio console for debugging
- Debugger support (WinDbg?)


Asynchronous Programming in Rust › Tools for async programming › Profiling

- How async messes up flamegraphs
- How to profile async IO
- Getting insight into the runtime
  - Tokio metrics


Asynchronous Programming in Rust › Destruction and clean-up

- Object destruction and recap of Drop
- General clean up requirements in software
- Async issues
  - Might want to do stuff async during clean up, e.g., send a final message
  - Might need to clean up stuff which is still being used async-ly
  - Might want to clean up when an async task completes or cancels and there is no way to catch that
  - State of the runtime during clean-up phase (esp if we're panicking or whatever)
  - No async Drop
    - WIP
  - forward ref to completion io topic


Asynchronous Programming in Rust › Destruction and clean-up › Cancellation

- How it happens (recap of more-async-await.md)
  - drop a future
  - cancellation token
  - abort functions
- What we can do about 'catching' cancellation
  - logging or monitoring cancellation
- How cancellation affects other futures tasks (forward ref to cancellation safety chapter, this should just be a heads-up)


Asynchronous Programming in Rust › Destruction and clean-up › Panicking and async

- Propagation of panics across tasks (spawn result)
- Panics leaving data inconsistent (tokio mutexes)
- Calling async code when panicking (make sure you don't)

Destruction and clean-up
Panicking and async


Asynchronous Programming in Rust › Destruction and clean-up › Patterns for clean-up

- Avoid needing clean up (abort/restart)
- Don't use async for cleanup and don't worry too much
- async clean up method + dtor bomb (i.e., separate clean-up from destruction)
- centralise/out-source clean-up in a separate task or thread or supervisor object/process
- https://tokio.rs/tokio/topics/shutdown

Destruction and clean-up
Patterns for clean-up


Asynchronous Programming in Rust › Destruction and clean-up › Why no async Drop (yet)

- Note this is advanced section and not necessary to read
- Why async Drop is hard
- Possible solutions and there issues
- Current status

Destruction and clean-up
Why no async Drop (yet)


Asynchronous Programming in Rust › Futures

We've talked a lot about futures in the preceding chapters; they're a key part of Rust's async programming story! In this chapter we're going to get into some of the details of what futures are and how they work, and some libraries for working directly with futures.


Asynchronous Programming in Rust › Futures › The `Future` and `IntoFuture` traits

- Future
  - Output assoc type
  - No real detail here, polling is in the next section, reference adv sections on Pin, executors/wakers
- IntoFuture
  - Usage - general, in await, async builder pattern (pros and cons in using)
- Boxing futures, `Box<dyn Future>` and how it used to be common and necessary but mostly isn't now, except for recursion, etc.

Futures
The `Future` and `IntoFuture` traits


Asynchronous Programming in Rust › Futures › Polling

- what it is and who does it, Poll type
  - ready is final state
- how it connects with await
- drop = cancel
  - for futures and thus tasks
  - implications for async programming in general
  - reference to chapter on cancellation safety


Asynchronous Programming in Rust › Futures › futures-rs crate

- History and purpose
  - see streams chapter
  - helpers for writing executors or other low-level futures stuff
    - pinning and boxing
  - executor as a partial runtime (see alternate runtimes in reference)
- TryFuture
- convenience futures: pending, ready, ok/err, etc.
- combinator functions on FutureExt
- alternative to Tokio stuff
  - functions
  - IO traits


Asynchronous Programming in Rust › Futures › futures-concurrency crate

https://docs.rs/futures-concurrency/latest/futures_concurrency/


Asynchronous Programming in Rust › Runtimes and runtime issues › Running async code

- Explicit startup vs async main
- tokio context concept
- block_on
- runtime as reflected in the code (Runtime, Handle)
- runtime shutdown

Runtimes and runtime issues
Running async code


Asynchronous Programming in Rust › Runtimes and runtime issues › Threads and tasks

- default work stealing, multi-threaded
  - revisit Send + 'static bounds
- yield
- spawn-local
- spawn-blocking (recap), block-in-place
- tokio-specific stuff on yielding to other threads, local vs global queues, etc

Runtimes and runtime issues
Threads and tasks


Asynchronous Programming in Rust › Runtimes and runtime issues › Configuration options

- thread pool size
- single threaded, thread per core etc.

Runtimes and runtime issues
Configuration options


Asynchronous Programming in Rust › Runtimes and runtime issues › Alternate runtimes

- Why you'd want to use a different runtime or implement your own
- What kind of variations exist in the high-level design
- Forward ref to adv chapters

Runtimes and runtime issues
Alternate runtimes


Asynchronous Programming in Rust › Timers and Signal handling › Time and Timers

- runtime integration, don't use thread::sleep, etc.
- std Instant and Duration
- sleep
- interval
- timeout
  - special future vs select/race

Timers and Signal handling
Time and Timers


Asynchronous Programming in Rust › Timers and Signal handling › Signal handling

- what is signal handling and why is it an async issue?
- very OS specific
- see Tokio docs

Timers and Signal handling
Signal handling


Asynchronous Programming in Rust › Async iterators (FKA streams)

- Stream as an async iterator or as many futures
- WIP
  - current status
  - futures and Tokio Stream traits
  - nightly trait
- lazy like sync iterators
- pinning and streams (forward ref to pinning chapter)
- fused streams


Asynchronous Programming in Rust › Async iterators (FKA streams) › Consuming an async iterator

- while let with async next
- for_each, for_each_concurrent
- collect
- into_future, buffered

Async iterators (FKA streams)
Consuming an async iterator


Asynchronous Programming in Rust › Async iterators (FKA streams) › Stream combinators

- Taking a future instead of a closure
- Some example combinators
- unordered variations
- StreamGroup

Async iterators (FKA streams)
Stream combinators


Asynchronous Programming in Rust › Async iterators (FKA streams) › Stream combinators › join/select/race with streams

- hazards with select in a loop
- fusing
- difference to just futures
- alternatives to these
  - Stream::merge, etc.

Async iterators (FKA streams)
Stream combinators
join/select/race with streams


Asynchronous Programming in Rust › Async iterators (FKA streams) › Implementing an async iterator

- Implementing the trait
- Practicalities and util functions
- async_iter stream macro

Async iterators (FKA streams)
Implementing an async iterator


Asynchronous Programming in Rust › Async iterators (FKA streams) › Sinks

- https://docs.rs/futures/latest/futures/sink/index.html


Asynchronous Programming in Rust › Async iterators (FKA streams) › Future work

- current status
  - https://rust-lang.github.io/rfcs/2996-async-iterator.html
- async next vs poll
- async iteration syntax
- (async) generators
- lending iterators

Async iterators (FKA streams)
Future work


Asynchronous Programming in Rust › Cancellation and cancellation safety

Internal vs external cancellation
Threads vs futures
  drop = cancel
  only at await points
  useful feature
  still somewhat abrubt and surprising
Other cancellation mechanisms
  abort
  cancellation tokens


Asynchronous Programming in Rust › Cancellation and cancellation safety › Cancellation safety

Not a memory safety issue or race condition
  Data loss or other logic errors
Different definitions/names
  tokio's definition
  general definition/halt safety
  applying a replicated future idea
Simple data loss
Resumption
Issue with select or similar in loops
Splitting state between the future and the context as a root cause

Cancellation and cancellation safety
Cancellation safety


Asynchronous Programming in Rust › Pinning

Pinning is a notoriously difficult concept and has some subtle and confusing properties. This section will go over the topic in depth (arguably too much depth). Pinning is key to the implementation of async programming in Rust[^design], but it's possible to get far without ever encountering pinning and certainly without having to have a deep understanding.
The first section will give a summary of pinning, which hopefully is enough for most async programmers to know. The rest of this chapter is for implementers, others doing advanced or low-level async programming, and the curious.
After the summary, this chapter will give some background on move semantics before getting into pinning. We'll cover the general idea, then the `Pin` and `Unpin` types, how pinning achieves it goals, and several topics about working with pinning in practice. There are then sections on pinning and async programming, and some alternatives and extensions to pinning (for the really curious). At the end of the chapter are some links to alternative explanations and reference material.
[^design]: It's worth noting that pinning is a low-level building block designed specifically for the implementation of async Rust. Although it is not directly tied to async Rust and can be used for other purposes, it was not designed to be a general-purpose mechanism, and in particular is not an out-of-the-box solution for self-referential fields. Using pinning for anything other than async code generally only works if it is wrapped in thick layers of abstraction, since it will require lots of fiddly and hard to reason about unsafe code.


Asynchronous Programming in Rust › Pinning › TL;DR

`Pin` marks a pointer as pointing to an object which will not move until it is dropped. Pinning is not built-in to the language or compiler; it works by simply restricting access to mutable references to the pointee. It is easy enough to break pinning in unsafe code, but like all safety guarantees in unsafe code, it is the responsibility of the programmer not to do so.
By guaranteeing that an object won't move, pinning makes it safe to have references from one field of a struct to another (sometimes called self-references). This is required for the implementation of async functions (which are implemented as data structures where variables are stored as fields, since variables may reference each other, fields of a future implementing an async function must be able to reference each other). Mostly, programmers don't have to be aware of this detail, but when dealing with futures directly, you might need to be because the signature of `Future::poll` requires `self` to be pinned.
If you're using futures by reference, you might need to pin a reference using `pin!(...)` to ensure the reference still implements the `Future` trait (this often comes up with the `select` macro). Likewise, if you want to manually call `poll` on a future (usually because you are implementing another future), you will need a pinned reference to it (use `pin!` or ensure arguments have pinned types). If you're implementing a future or if you have a pinned reference for some other reason, and you want mutable access to the object's internals, you'll need to understand the section below on pinned fields to know how to do so and when it is safe.


Asynchronous Programming in Rust › Pinning › Move semantics

A useful concept for discussing pinning and related topics is the idea of *place*s. A place is a chunk of memory (with an address) where a value can live. A reference doesn't really point at a value, it points at a place. That is why `*ref = ...` makes sense: the dereference gives you the place, not a copy of the value. Places are well-known to language implementers but usually implicit in programming languages (they are implicit in Rust). Programmers usually have a good intuition for places, but may not think of them explicitly.
As well as references, variables and field accesses evaluate to places. In fact, anything that can appear on the left-hand side of an assignment must be a place at runtime (which is why places are called 'lvalue's in compiler jargon).
In Rust, mutability is a property of places, as is being 'frozen' as a result of borrowing (we might say the place is borrowed).
Assignment in Rust *moves* data (mostly, some simple data has copy semantics, but that doesn't matter too much). When we write `let b = a;`, the data that was in memory at a place identified by `a` is moved to the place identified by `b`. That means that after the assignment, the data exists at `b` but no longer exists at `a`. Or in other words, the address of the object is changed by the assignment[^compiler].
If pointers existed to the place which was moved from, the pointers would be invalid since they no longer point to the object. This is why borrowed references prevent moving: `let r = &a; let b = a;` is illegal, the existence of `r` prevents `a` being moved.


Asynchronous Programming in Rust › Pinning › Move semantics

The compiler only knows about references from outside an object into the object (such as the above example, or a reference to a field of an object). A reference entirely within an object would be invisible to the compiler. Imagine if we were allowed to write something like:
```rust,norun
struct Bad {
    field: u64,
    r: &'self u64,
}
```
We could have an instance `b` of `Bad` where `b.r` points to `b.field`. In `let a = b;`, the internal reference `b.r` to `b.field` is invisible to the compiler, so it looks like there are no references to `b` and therefore the move to `a` would be ok. However if that happened, then after the move, `a.r` would not point to `a.field` as we'd like, but to invalid memory at the old location of `b.field`, violating Rust's safety guarantees.
Moving data isn't limited to values. Data can also be moved out of a unique reference. Dereferencing a `Box` moves the data from the heap to the stack. `take`, `replace`, and `swap` (all in `std::mem`) move data out of a mutable reference (`&mut T`). Moving out of a `Box` leaves the pointed-to place invalid. Moving out of a mutable reference leaves the place valid, but containing different data.
[^compiler]: We're conflating source code and runtime a bit here. To be absolutely clear, variables don't exist at runtime. The (compiled) snippet might be executed multiple times (e.g., if it's in a loop or in a function called multiple times). For each execution the variables in the source code will be represented by different addresses at runtime.


Asynchronous Programming in Rust › Pinning › Move semantics

Abstractly, a move is implemented by copying the bits from the origin to the destination and then erasing the origin bits. However, the compiler can optimise this is many ways.


Asynchronous Programming in Rust › Pinning › Pinning

Important note: I'm going to start by discussing an abstract concept of pinning, which is not exactly what is expressed by any particular type. We'll make the concept more concrete as we go on, and end up with precise definitions of what different types mean, but none of these types mean exactly the same as the pinning concept we'll start with.
An object is pinned if it will not be moved or otherwise invalidated. As I explained above, this is not a new concept - borrowing an object prevents the object being moved for the duration of the borrow. Whether an object can be moved or not is not explicit in Rust's types, though it is known by the compiler (which is why you can get "cannot move out of" error messages). As opposed to borrowing (and the temporary restriction on moves caused by borrowing), being pinned is permanent. An object can change from being not pinned to being pinned, but once it is pinned then it must remain pinned until it is dropped[^inherent].
Just as pointer types reflect the ownership and mutability of the pointee (e.g., `Box` vs `&`, `&mut` vs `&`), we want to reflect pinned-ness in pointer types too. This is not a property of the pointer - the pointer is not pinned or movable - it is a property of the pointed-to place: whether the pointee can be moved out of its place.
Roughly, `Pin<Box<T>>` is a pointer to an owned, pinned object and `Pin<&mut T>` is a pointer to a uniquely borrowed, mutable, pinned object (c.f., `&mut T` which is a pointer to a uniquely borrowed, mutable, object which may or may not be pinned).


Asynchronous Programming in Rust › Pinning › Pinning

The pinning concept was not added to Rust until after 1.0 and for reasons of backwards compatibility, there is no way to explicitly express whether an *object* is pinned or not. We can only express that a reference points to a pinned or not-pinned object.
Pinning is orthogonal to mutability. An object might be mutable and either pinned (`Pin<&mut T>`) or not (`&mut T`) (i.e., the object can be modified, and either it is pinned in place or can be moved), or immutable and either pinned (`Pin<&T>`) or not (`T`) (i.e., the object can't be modified, and either it can't be moved or can be moved but not modified). Note that `&T` cannot be mutated or moved, but is not pinned because its immovability is only temporary.
[^inherent]: Permanence is not a fundamental aspect of pinning, it is part of the framing of pinning in Rust and the safety guarantees around it. It would be ok for pinning to be temporary if this could be safely expressed and the temporal scope of pinning could be relied upon by consumers of the pinning guarantees. However, that is not possible with Rust today or with any reasonable extension.


Asynchronous Programming in Rust › Pinning › Pinning › `Unpin`

Although moving and not moving is how we introduced pinning and is somewhat suggested by the name, `Pin` does not actually tell you much about whether the pointee will actually move or not.
What? Sigh.
Pinning is actually a contract about validity, not about moving. It guarantees that *if an object is address-sensitive, then* its address will not change (and thus addresses derived from it, such as the addresses of its fields, will not change either). Most data in Rust is not address-sensitive. It can be moved around and everything will be ok. `Pin` guarantees that the pointee will be valid with respect to it's address. If the pointee is address-sensitive, then it can't be moved; if it's not address-sensitive, then it doesn't matter whether it is moved.
`Unpin` is a trait which expresses whether objects are address-sensitive. If an object implements `Unpin`, then it is *not* address-sensitive. If an object is `!Unpin` then it is address-sensitive. Alternatively, if we think of pinning as the act of holding an object in its place, then `Unpin` means it is safe to undo that action and allow the object to be moved.
`Unpin` is an auto-trait and most types are `Unpin`. Only types which have an `!Unpin` field or which explicitly opt-out are not `Unpin`. You can opt-out by having a `PhantomPinned` field or (if you're using nightly) with `impl !Unpin for ... {}`.


Asynchronous Programming in Rust › Pinning › Pinning › `Unpin`

For types which implement `Unpin`, `Pin` essentially does nothing. `Pin<Box<T>>` and `Pin<&mut T>` can be used just like `Box<T>` and `&mut T`. In fact, for `Unpin` types, the `Pin`ed and regular pointers can be freely-interconverted using `Pin::new` and `Pin::into_inner`. It's worth restating: `Pin<...>` does not guarantee that the pointee will not move, only that the pointee won't move if it is `!Unpin`.
The practical implication of the above is that working with `Unpin` types and pinning is much easier than with types which are not `Unpin`, in fact the `Pin` marker has basically no effect on `Unpin` types and pointers to `Unpin` types, and you can basically ignore all the pinning guarantees and requirements.
`Unpin` should not be understood as a property of an object alone; the only thing `Unpin` changes is how an object interacts with `Pin`. Using an `Unpin` bound outside of the pinning context doesn't affect the compiler's behaviour or what can be done with the object. The only reason to use `Unpin` is in conjunction with pinning, or to propagate the bound to where it is used with pinning.


Asynchronous Programming in Rust › Pinning › Pinning › `Pin`

`Pin` is a marker type, it is important for type checking, but is compiled away and does not exist at runtime (`Pin<Ptr>` is guaranteed to have the same memory layout and ABI as `Ptr`). It is a wrapper of pointers (such as `Box`), so it behaves like a pointer type, but it does not add an indirection, `Box<Foo>` and `Pin<Box<Foo>>` are the same when a program is run. It is better to think of `Pin` as a modifier to the pointer rather than a pointer itself.
`Pin<Ptr>` means that the pointee of `Ptr` (not `Ptr` itself) is pinned. That is, `Pin` guarantees that the pointee (not the pointer) will remain valid with respect to its address until the pointee is dropped. If the pointee is address-sensitive (i.e., is `!Unpin`), then the pointee will not be moved.


Asynchronous Programming in Rust › Pinning › Pinning › Pinning values

Objects are not created pinned. An object starts unpinned (and may be freely moved), it becomes pinned when a pinning pointer is created which points to the object. If the object is `Unpin`, then this is trivial using `Pin::new`, however, if the object is not `Unpin`, then pinning it must ensure that it cannot be moved or invalidated via an alias.
To pin an object on the heap, you can create a new pinning `Box` by using `Box::pin`, or convert an existing `Box` into a pinning `Box` using `Box::into_pin`. In either case, you'll end up with `Pin<Box<T>>`. Some other pointers (such as `Arc` and `Rc`) have similar mechanisms. For pointers which don't, or for your own pointer types, you'll need to use `Pin::new_unchecked` to create a pinned pointer[^box-pin]. This is an unsafe function and so the programmer must ensure that `Pin`'s invariants are maintained. That is, that the pointee will, under every circumstance, remain valid until it's destructor is called. There are some subtle details to ensuring this, refer to the function's docs or the below section how pinning works for more.


Asynchronous Programming in Rust › Pinning › Pinning › Pinning values

`Box::pin` pins an object to a place in the heap. To pin an object on the stack, you can use the `pin` macro to create and pin a mutable reference (`Pin<&mut T>`)[^not-stack].
Tokio also has a `pin` macro which does the same thing as the std macro and also supports assigning into a variable inside the macro. The futures-rs and pin-utils crates have a `pin_mut` macro which used to be commonly used, but is now deprecated in favor of the std macro.
You can also use `Pin::static_ref` and `Pin::static_mut` to pin a static reference.
[^box-pin]: There is no special treatment for `Box` (or the other std pointers) either in the pinning implementation or the compiler. `Box` uses the unsafe functions in `Pin`'s API to implement `Box::pin`. The safety requirements of `Pin` are satisfied due to the safety guarantees of `Box`.
[^not-stack]: This is only strictly pinning to the stack in non-async functions. In an async function, all locals are allocated in the async pseudo-stack, so the place being pinned is likely to be stored on the heap as part of the future underlying the async function.


Asynchronous Programming in Rust › Pinning › Pinning › Using pinned types

In theory, using pinned pointers is just like using any other pointer type. However, because it is not the most intuitive abstraction, and because it has no language support, using pinned pointers tends to be pretty unergonomic. The most common case for using pinning is when dealing with futures and streams, we'll cover those specifics in more detail below.
Using a pinned pointer as an immutably borrowed reference is trivial because of `Pin`'s implementation of `Deref`. You can mostly just treat `Poll<Ptr<T>>` as `&T`, using an explicit `deref()` if necessary. Likewise, getting a `Pin<&T>` is pretty easy using `as_ref()`.
The most common way to work with pinned types is using `Pin<&mut T>` (e.g., in `Future::poll`), however, the easiest way to produce a pinned object is `Box::pin` which gives a `Pin<Box<T>>`. You can convert the latter to the former using `Pin::as_mut`. However, without the language support for reusing references (implicit reborrowing), you have to keep calling `as_mut` rather than reusing the result. E.g. (from the `as_mut` docs),
```rust,norun
impl Type {
    fn method(self: Pin<&mut Self>) {
        // do something
    }

    fn call_method_twice(mut self: Pin<&mut Self>) {
        // `method` consumes `self`, so reborrow the `Pin<&mut Self>` via `as_mut`.
        self.as_mut().method();
        self.as_mut().method();
    }
}
```


Asynchronous Programming in Rust › Pinning › Pinning › Using pinned types

If you need to access the pinned pointee in some other way, you can do so via `Pin::into_inner_unchecked`. However, this is unsafe and you must be *very* careful about ensuring the safety requirements of `Pin` are respected.


Asynchronous Programming in Rust › Pinning › Pinning › How pinning works

`Pin` is a simple wrapper struct (aka, a newtype) for pointers. It is enforced to work only on pointers by requiring the `Deref` bound on it's generic parameter to do anything useful, however, this is just for expressing intention, rather than for preserving safety. As with most newtype wrappers, `Pin` exists to express an invariant at compile-time rather than for any runtime effect. Indeed, in most circumstances, `Pin` and the pinning machinery will completely disappear during compilation.
To be precise, the invariant expressed by `Pin` is about validity, not just movability. It is also a validity invariant which only applies once a pointer is pinned - before that `Pin` has no effect and makes no requirements on what happens before something is pinned. Once a pointer is pinned, `Pin` requires (and guarantees in safe code) that the pointed-to object will remain valid at the same address in memory until the object's destructor is called.
For immutable pointers (e.g., borrowed references), `Pin` has no effect - since the pointee cannot be mutated or replaced, there is no danger of it being invalidated.
For a pointer that allows mutation (e.g., `Box` or `&mut`), having direct access to that pointer or access to a mutable reference (`&mut`) to the pointee could allow for mutation or moving the pointee. `Pin` simply does not provide any (non-`unsafe`) way to get direct access to the pointer or a mutable reference. The usual way for a pointer to provide a mutable reference to its pointee is by implementing `DerefMut`, `Pin` only implements `DerefMut` if the pointee is `Unpin`.


Asynchronous Programming in Rust › Pinning › Pinning › How pinning works

This implementation is incredibly simple! To summarize: `Pin` is a wrapper struct around a pointer which provides only immutable access to the pointee (and mutable access if the pointee is `Unpin`). Everything else is details (and subtle invariants for unsafe code). For convenience, `Pin` provides a facility to convert between `Pin` types (always safe since the pointer cannot escape a `Pin`), etc.
`Pin` also provides unsafe functions for creating pinned pointers and accessing the underlying data. As with all `unsafe` functions, maintaining the safety invariants is the responsibility of the programmer rather than the compiler. Unfortunately, the safety invariants for pinning are somewhat scattered, in that they are enforced in different places and are hard to describe in a global, unified manner. I won't describe them in detail here and refer you to the docs, but I'll attempt to summarize (see the module docs for a detailed overview):


Asynchronous Programming in Rust › Pinning › Pinning › How pinning works › Pinning pointer types

- Creating a new pinned pointer `new_unchecked`. The programmer must ensure that the pointee is pinned (that is, abides by the pinning invariants). This requirement may be satisfied by the pointer type alone (e.g., in the case of `Box`) or may require participation of the pointee type (e.g., in the case of `&mut`). This includes (but is not limited to):
  - Not moving out of `self` in `Deref` and `DerefMut`.
  - Properly implementing `Drop`, see the drop guarantee.
  - Opting out of `Unpin` (by using `PhantomPinned`) if you require the pinning guarantees.
  - The pointee may not be `#[repr(packed)]`.
- Accessing the pinned value `into_inner_unchecked`, `get_unchecked_mut`, `map_unchecked`, and `map_unchecked_mut`. It becomes the programmer's responsibility to enforce the pinning guarantees (including not moving the data) from the moment data is accessed until it's destructor runs (note that this scope of responsibility extends beyond the unsafe call and applies whatever happens to the underlying data).
- Not providing any other way to move data out of a pinned type (which would need an unsafe implementation).

Pinning
Pinning
How pinning works
Pinning pointer types


Asynchronous Programming in Rust › Pinning › Pinning › How pinning works › Pinning pointer types

We said earlier that `Pin` wraps a pointer type. It is common to see `Pin<Box<T>>`, `Pin<&T>`, and `Pin<&mut T>`. Technically, the only requirement of the pinning pointer type is that it implements `Deref`. However, there are no ways to create a `Pin<Ptr>` for any other pointer types other than using unsafe code (via `new_unchecked`). Doing so has requirements on the pointer type to ensure the pinning contract:
- The pointer's implementations of `Deref` and `DerefMut` must not move out of their pointee.
- It must not be possible to obtain an `&mut` reference to the pointee at any time after the `Pin` is created, even after the `Pin` has been dropped (this is why you can't safely construct a `Pin<&mut T>` from an `&mut T`). This must remain true via multiple steps or via references (which prevents using `Rc` or `Arc`).
- The pointer's implementation of `Drop` must not move (or otherwise invalidate) it's pointee.
See the `new_unchecked` docs for more detail.


Asynchronous Programming in Rust › Pinning › Pinning › Pinning and `Drop`

The pinning contract applies until the pinned object is dropped (technically, that means when its `drop` method returns, not when it is called). This is usually fairly straightforward since `drop` is called automatically when objects are destroyed. If you are doing things manually with an object's lifecycle, you might need to give it some extra thought. If you have an object which is (or might be) pinned and that object is not `Unpin`, then you must call it's `drop` method (using `drop_in_place`) before deallocating or reusing the object's memory or address. See the std docs for details.
If you are implementing an address-sensitive type (i.e., one that is `!Unpin`), then you must take extra care with the `Drop` implementation. Even though the self-type in `drop` is `&mut Self`, you must treat the self-type as `Pin<&mut Self>`. In other words, you must ensure the object remains valid until the `drop` function returns. One way to make this explicit in the source code is to follow the following idiom:
```rust,norun
impl Drop for Type {
    fn drop(&mut self) {
        // `new_unchecked` is okay because we know this value is never used
        // again after being dropped.
        inner_drop(unsafe { Pin::new_unchecked(self)});

        fn inner_drop(this: Pin<&mut Self>) {
            // Actual drop code goes here.
        }
    }
}
```


Asynchronous Programming in Rust › Pinning › Pinning › Pinning and `Drop`

Note that the validity requirements will be dependent on the type being implemented. Precisely defining these requirements, especially concerning object destruction is recommended, especially if multiple objects could be involved (e.g., an intrusive linked list). Ensuring correctness here is likely to be interesting!


Asynchronous Programming in Rust › Pinning › Pinning › Pinned self in methods

Calling methods on pinned types leads to thinking about the self-type in these methods. If the method does not need to mutate `self`, then you can still use `&self` since `Pin<...>` can dereference to a borrowed reference. However, if you need to mutate `self` (and your type is not `Unpin`) then you need to choose between `&mut self` and `self: Pin<&mut Self>` (although pinned pointers can't be implicitly coerced to the latter type, they can be easily converted using `Pin::as_mut`).
Using `&mut self` makes the implementation easy, but means the method cannot be called on a pinned object. Using `self: Pin<&mut Self>` means considering pin projection (see the next section) and can only be called on a pinned object. Although this is all a bit confounding, it makes sense intuitively when you remember that pinning is a phased concept - objects start unpinned, and at some point undergo a phase change to become pinned. `&mut self` methods are ones which can be called in the first (unpinned) phase and `self: Pin<&mut Self>` methods are ones which can be called in the second (pinned) phase.
Note that `drop` takes `&mut self` (even though it might be called in either phase). This is due to a limitation of the language and the desire for backwards compatibility. It requires special treatment in the compiler and comes with safety requirements.


Asynchronous Programming in Rust › Pinning › Pinning › Pinned fields, structural pinning, and pin projection

Given that an object is pinned, what does that tell us about the 'pinned'-ness of its fields? The answer depends on choices made by the implementer of the datatype, there is no universal answer (indeed it can be different for different fields of the same object).
If the pinned-ness of an object propagates to a field, we say the field exhibits 'structural pinning' or that pinning is projected with the field. In this case there should be a projection method `fn get_field(self: Pin<&mut Self>) -> Pin<&mut Field>`. If the field is not structurally pinned, then a projection method should have signature `fn get_field(self: Pin<&mut Self>) -> &mut Field`. Implementing either method (or implementing similar code) requires `unsafe` code and either choice has safety implications. Pin-propagation must be consistent, a field must always be structurally pinned or not, it is nearly always unsound for a field to be structurally pinned at some times and not at others.
Pinning should project to a field if the field is an address-sensitive part of the aggregate datatype. That is, if the aggregate being pinned depends on the field being pinned, then pinning must project to that field. For example, if there is a reference from another part of the aggregate into the field, or if there is a self-reference within the field, then pinning must project to the field. On the other hand, for a generic collection, pinning does not need to project to it's contents since the collection does not rely on their behaviour (that's because the collection cannot rely on the implementation of the generic items it contains, so the collection itself cannot rely on the addresses of its items).


Asynchronous Programming in Rust › Pinning › Pinning › Pinned fields, structural pinning, and pin projection › Macros for pin projection

When writing unsafe code, you can only assume that the pinning guarantees apply to the fields of an object which are structurally pinned. On the other hand, you can safely treat non-structurally pinned fields as moveable and not worry about the pinning requirements for them. In particular, a struct can be `Unpin` even if a field is not, as long as that field is always treated as not being structurally pinned.
If a field is structurally pinned, then the pinning requirements on the aggregate struct extend to the field. Under no circumstance can code move the contents of the field while the aggregate is pinned (this would always require unsafe code). Structurally pinned fields must be dropped before they are moved (including deallocation) even in the case of panicking, which means care must be taken within the aggregate's `Drop` impl. Furthermore, the aggregate struct cannot be `Unpin` unless all of its structurally-pinned fields are.
There are macros available for helping with pin projection.
The pin-project crate provides the `#[pin_project]` attribute macro (and the `#[pin]` helper attribute) which implements safe pin projection for you by creating a pinned version of the annotated type which can be accessed using the `project` method on the annotated type.
Pin-project-lite is an alternative using a declarative macro (`pin_project!`) which works in a very similar way to pin-project. Pin-project-lite is lightweight in the sense that it is not a procedural macro and therefore does not add dependences for implementing procedural macros to your project. However, it is less expressive than pin-project and does not give custom error messages. Pin-project-lite is recommended if you want to avoid adding the procedural macro dependencies, and pin-project is recommended otherwise.


Asynchronous Programming in Rust › Pinning › Pinning › Pinned fields, structural pinning, and pin projection › Macros for pin projection

Pin-utils provides the `unsafe_pinned` macro to help implement pin projection, but the whole crate is deprecated in favor of the above crates and functionality now in std.


Asynchronous Programming in Rust › Pinning › Pinning › Assigning to a pinned pointer

It is generally safe to assign into a pinned pointer. Although this can't be done in the usual way (`*p = ...`), it can be done using `Pin::set`. More generally, you can use unsafe code to assign into fields of the pointee.
Using `Pin::set` is always safe since the previously pinned pointee will be dropped, fulfilling the pin requirements and the new pointee is not pinned until the move into the pinned place is complete. Assigning into individual fields does not automatically violate the pinning requirements, but care must be taken to ensure that the object as a whole remains valid. For example, if a field is assigned into, then any other fields which reference that field must still be valid with the new object (this is not part of the pinning requirements, but might be part of the object's other invariants).
Copying one pinned object into another pinned place can only be done in unsafe code, how safety is maintained depends on the individual object. There is no general violation of the pinning requirements - the object being replaced is not moving and nor is the object being copied. However, the validity of the object being replaced may have safety requirements which are usually protected by pinning, but in this case must be established by the programmer. For example, if we have a struct with two fields `a` and `b` where `b` refers to `a`, that reference requires pinning to be remain valid. If such a struct is copied into another place, then the value of `b` must be updated to point to the new `a` rather than the old one.

Pinning
Pinning
Assigning to a pinned pointer


Asynchronous Programming in Rust › Pinning › Pinning and async programming

Hopefully, you can do all you ever want to do with async Rust and never worry about pinning. Sometimes you'll hit a corner case which requires using pinning and if you want to do implement futures, a runtime, or similar things, you'll need to know about pinning. In this section, I'll explain why.
Async functions are implemented as futures (see section TODO - this is a summary overview, make sure we explain more deeply and with examples elsewhere). At each await point execution of the function may be paused and during that time the values of live variables must be saved. They essentially become fields of a struct (which is part of an enum). Such variables may refer to other variables which are saved in the future, e.g., consider,
```rust,norun
async fn foo() {
  let a = ...;
  let b = &a;
  bar().await;
  // use b
}
```
The generated future object here will be something like:
```rust,norun
struct Foo {
  a: A,
  b: &'self A,  // Invariant `self.b == &self.a`
}
```
(I'm simplifying a bit, ignoring the state of execution, etc., but the important bit is the variables/fields).
This makes intuitive sense, unfortunately `'self` does not exist in Rust. And for good reason! Remember that Rust objects can be moved, so code like the following would be unsound:
```rust,norun
let f1 = Foo { ... }; // f1.b == &f1.a
let f2 = f1; // f2.b == &f1.a, but f1 no longer exists since it moved to f2
```
Note that this is not just an issue of not being able to name the lifetime, even if we use raw pointers, such code would still be incorrect.


Asynchronous Programming in Rust › Pinning › Pinning and async programming

However, if we know that once it is created, then an instance of `Foo` will never move, then everything Just Works. (The compiler has a concept similar to `'self` internally for such cases, as a programmer, we would have to use raw pointers and unsafe code). This concept of not moving is exactly what pinning describes.
We see this requirement in the signature of `Future::poll`, where the type of `self` (the future) is `Pin<&mut Self>`. Mostly, when using async/await, the compiler takes care of pinning and unpinning, and as a programmer you don't need to worry about it.


Asynchronous Programming in Rust › Pinning › Pinning and async programming › Manual pinning

There are some places where pinning leaks through the abstraction of async/await. At its root, this is due to the `Pin` in the signature of `Future::poll` and `Stream::poll_next`. When using futures and streams directly (rather than through async/await), we might need to consider pinning to make things work. Some common reasons to need pinned types are:
- Polling a future or stream - either in application code or when implementing your own future.
- Using boxed futures. If you're using boxed futures (or streams) and therefore writing out future types rather than using async functions, you'll likely see a lot of `Pin<...>` in those types and need to use `Box::pin` to create the futures.
- Implementing a future - inside `poll`, `self` is pinned and therefore you need to work with pin projection and/or unsafe code to get mutable access to fields of `self`.
- Combining futures or streams. This mostly just works, but if you need to take a reference to a future and then poll it (e.g., defining a future outside a loop and using it in `select!` inside the loop), then you will need to pin the reference to the future in order to use the reference like a future.
- Working with streams - there is currently less abstraction in Rust around streams than futures, so you're more likely to use combinator methods (which don't technically require pinning, but seems to make issues around referencing or creating futures/streams more prevalent) or even `poll` manually than when working with futures.

Pinning
Pinning and async programming
Manual pinning


Asynchronous Programming in Rust › Pinning › Alternatives and extensions

This section is for those with a curiosity about the language design around pinning. You absolutely don't need to read this section if you just want to read, understand, and write async programs.
Pinning is difficult to understand and can feel a bit clunky, so people often wonder if there is a better alternative or variation. I'll cover a few alternatives and show why they either don't work or are more complex than you might expect.
However before that, it's important to understand the historical context for pinning. If you are designing a brand new language and want to support async/await, self-references, or immovable types there are certainly better ways to do so than Rust's pinning. However, async/await, futures, and pinning were added to Rust after it's 1.0 release and designed in the context of a strong backwards-compatibility guarantee. Beyond that hard requirement, there was a requirement of wanting to design and implement this feature in a reasonable time frame. Some solutions (e.g., those involving linear types) would require fundamental research, design, and implementation that would realistically be measured in decades when considering the resources and constraints of the Rust project.


Asynchronous Programming in Rust › Pinning › Alternatives and extensions › Alternatives

First, lets consider the class of solutions which make Rust types non-movable by default. Note that this is a significant change to the fundamental semantics of Rust; any solution in this class would likely need significant effort to achieve backwards-compatibility (I won't speculate on if that's even possible for specific solutions, but with techniques like auto-traits, derive attributes, editions, migration tooling, etc., it is possibly possible).
One proposal (really, a group of proposals since there are various ways to define the semantics) is to have a `Move` marker trait (similar to `Copy`) which marks objects as movable and all other types would be immovable. In contrast to `Pin`, this is a property of values, not of pointers, so the effect is much more far-reaching, e.g., `let a = b;` would be an error if `b` does not implement `Move`.
The fundamental problem with this approach is that pinning today is a phased concept (a place starts unpinned and becomes pinned) and types apply to the whole lifetime of values. (Pinning is also best understood as a property of places rather than values, but types apply to values, whether this is a fundamental problem for any trait-based approach, I don't know). This is explored in these two blog posts: Two Ways Not to Move and Ergonomic Self-Referential Types for Rust.
Furthermore, any `Move` trait is likely to have problems with backwards-compatibility and lead to 'infectious bounds' (i.e., `Move` or `!Move` would be required in many, many places).

Pinning
Alternatives and extensions
Alternatives


Asynchronous Programming in Rust › Pinning › Alternatives and extensions › Alternatives

Another proposal is to support move constructors similar to C++. However, this breaks the fundamental invariant of Rust that objects can always be bit-wise moved. That would make Rust much less predictable and therefore make Rust programs more difficult to understand and debug. This is a backwards-incompatible change of the worst kind because it would silently break unsafe code because it changes a fundamental assumption that authors of the code may have made. Furthermore, the design and implementation effort required for such a fundamental change would be huge. On top of those practical issues, it's unclear if it would even work: move constructors could be used to fix-up references in the object being moved, but there might be references to the object being moved from outside the object which could not be fixed up.
A potential solution of a different kind is the idea of offset references. This is a reference which is relative rather than absolute, i.e., a field which is an offset reference to another field would always point within the same object, even if the object is moved in memory. The issue with offset pointers is that a field must be either an offset pointer or an absolute pointer. But references in async function become fields which sometimes reference memory internal to the future object and sometimes reference memory outside it.


Asynchronous Programming in Rust › Pinning › Alternatives and extensions › Extensions

There are multiple proposals for making pinning more powerful and/or easier to work with. These are mostly proposals to make pinning a more first-class part of the language in various ways, rather than a purely library concept (they often include extensions to std as well as the language). I'll cover a few of the more developed ideas, they are related to each other and all have the general goal of improving pinning ergonomics by making creating and using pinned places easier, in particular around structural pinning and `drop`.
Pinned places runs with the idea that pinning is property of places rather than values or types, and adds a `pin`/`pinned` modifier to references similar to `mut`. This integrates with reborrowing and method resolution to improve the ergonomics of method calls with pinned `self`.
`UnpinCell` extends the pinned places idea to support native pin projection of fields. MinPin is a more minimal (and backwards-compatible) proposal for native pin projection and better `drop` support.
The `Overwrite` trait is a proposed trait which makes explicit the distinction between permission to modify a part of an object (`foo.f = ...`) and permission to overwrite the whole object (`*foo = ...`), both of which are currently allowed for all mutable references. The proposal also includes immutable fields. `Overwrite` is a sort-of-replacement for `Unpin` which (together with some of the ideas from pinned places) could improve working with pinning. Unfortunately, although it could be adopted backwards-compatibly, the transition would be a lot more work than for the other extensions.

Pinning
Alternatives and extensions
Extensions


Asynchronous Programming in Rust › Pinning › References

- std docs source of truth for behaviour and guarantees of `Pin`, etc. Good docs.
  - `Pin`, `Unpin`, `pin` macro
- RFC 2349 the RFC which proposed pinning. The stabilized API is a bit different from the one proposed here, but there is a good explanation of the core concept and rationale in the RFC.
- Some blog posts or other resources explaining pinning:
  - Pin by WithoutBoats (the primary designer of pinning) on the history, context, and rationale of pinning, and why it is a difficult concept.
  - Why is std::pin::Pin so weird? deep dive into the rationale of the pinning design and using pinning in practice.
  - Pin, Unpin, and why Rust needs them
  - Pinning section of async/await
  - Pin and suffering thorough blog post in a very conversational style about understanding async code and pinning with lots of examples.
  - The book *Rust for Rustaceans* by Jon Gjengset has an excellent description of why pinning is necessary for the implementation of async/await and how pinning works.


Asynchronous Programming in Rust › Structured Concurrency

Authors note (TODO): we might want to discuss some parts of this chapter much earlier in the book, in particularly as design principles (first intro is in guide/intro). However, in the interests of better understanding the topic and getting something written down, I'm starting with a separate chapter. It's also still a bit rough.
(Note: the first few sections are talking about the abstract concept of structured concurrency and is not specific to Rust or async programming (c.f., synchronous concurrent programming with threads). I use 'task' to mean any thread or async task or other similar concurrency primitive).
Structured concurrency is a philosophy for designing concurrent programs. For programs to fully adhere to the principals of structured concurrency requires certain language features and libraries, but many of the benefits are available by following the philosophy without such features. Structured concurrency is independent of language and concurrency primitives (threads vs async, etc.). Many people have found the ideas from structured concurrency to be useful when programming with async Rust.
The essential idea of structured concurrency is that tasks are organised into a tree. Child tasks start after their parents and always finish before them. This allows results and errors to always be passed back to parent tasks, and requires that cancellation of parents is always propagated to child tasks. Primarily, temporal scope follows lexical scope, which means that a task should not outlive the function or block where it is created. However, this is not a requirement of structured concurrency as long as longer-lived tasks are reified in the program in some way (typically by using an object to represent the temporal scope of a child task within its parent task).
TODO diagram
Structured concurrency is named by analogy to structured programming, which is the idea that control flow should be structured using functions, loops, etc., rather than arbitrary jumps (`goto`).


Asynchronous Programming in Rust › Structured Concurrency

Before we consider structured concurrency, it's helpful to reflect on the sense in which common concurrent designs are unstructured. A typical pattern is that a task is started using some kind of spawning statement. That task then runs to completion concurrently with other tasks in the system (including the task which spawned it). There is no constraint on which task finishes first. The program is essentially just a bag of tasks which live independently and might terminate at any time. Any communication or synchronization of the tasks is ad hoc, and the programmer cannot assume that any other task will still be running.
The practical downsides of unstructured concurrency are that returning results from a task must happen in an extra-linguistic fashion with no language-level guarantees around when or how this happens. Errors may go uncaught because languages' error handling mechanisms cannot be applied to the unconstrained control flow of unstructured concurrency. We also have no guarantees about the relative state of tasks - any task may be running, terminated successfully or with an error, or externally cancelled, independent of the state of any others[^join]. All this makes concurrent programs difficult to understand and maintain. This lack of structure is one reason why concurrent programming is considered categorically more difficult than sequential programming.
It's worth noting that structured concurrency is a programming discipline which imposes restrictions on your program. Just like functions and loops are less flexible than goto, structured concurrency is less flexible than just spawning tasks. However, as with structured programming the costs of structured concurrency in flexibility are outweighed by the gains in predictability.
[^join]: Using join handles mitigates these downsides somewhat, but is an ad hoc mechanism with no reliable guarantees. To get the full benefits of structured concurrency you have to be meticulous about always using them, as well as handling cancellation and errors properly. This is difficult without language or library support; we'll discuss this a bit more below.


Asynchronous Programming in Rust › Structured Concurrency › Principles of structured concurrency

The key idea of structured concurrency is that all tasks (or threads or whatever) are organized as a tree. I.e., each task (except the main task which is the root) has a single parent and there are no cycles of parents. A child task is started by its parent[^start-parent] and must *always* finish executing before its parent. There are no constraints between siblings. The parent of a task may not change.
When reasoning about programs which implement structured concurrency, the key new fact is that if a task is live, then all of its ancestor tasks must also be live. This doesn't guarantee they are in a good state - they might be in the process of shutting down or handling an error, but they must be running in some form. This means that for any task (except the root task), there is always a live task to send results or errors to. Indeed, the ideal approach is that the language's error handling is extended so that errors are always propagated to the parent task. In Rust, this should apply to both returning `Result::Err` and to panicking.
Furthermore, the lifetime of child tasks can be represented in the parent task. In the common case, the lifetime of a task (its temporal scope) is tied to the lexical scope in which it is started. For example, all tasks started within a function should complete before the function returns. This is an extremely powerful reasoning tool. Of course, this is too restrictive for all cases, and so the temporal scope of tasks can extend beyond a lexical scope by using an object in the program (often called a 'scope' or 'nursery'). Such an object can be passed or stored, and thus have an arbitrary lifetime. We still have an important reasoning tool: the tasks tied to that object cannot outlive it (in Rust this property lets us integrate tasks with the lifetime system).

Structured Concurrency
Principles of structured concurrency


Asynchronous Programming in Rust › Structured Concurrency › Principles of structured concurrency

The above leads to another benefit of structured concurrency: it lets us reason about resource management across multiple tasks. Cleanup code is called when a resource will no longer be used (e.g., closing a file handle). In sequential code, the problem of when to call cleanup code is solved by ensuring destructors are called when an object goes out of scope. However, in concurrent code, an object might still be in use by another task and so when to clean up is unclear (reference counting or garbage collection are solutions in many cases, but make reasoning about the lifetimes of objects difficult which can lead to errors, and also has runtime overheads).
The principle of a parent task outliving it's children has an important implication for cancellation: if a task is cancelled, then all its child tasks must be cancelled, and their cancellation must complete before the parent's cancellation completes. That in turn has implications for how cancellation can be implemented in a structurally concurrent system.
If a task completes early due to an error (in Rust, this might mean a panic, as well as an early return), then before returning the task must wait for all its child tasks to complete. In practice, an early return must trigger cancellation of child tasks. This is analogous to panicking in Rust: panicking triggers destructors in the current scope before walking up the stack, calling destructors in each scope until the program terminates or the panic is caught. Under structural concurrency, an early return must trigger cancellation of child tasks (and thus cleanup of objects in those tasks) and walks down the tree of tasks cancelling all (transitive) children.


Asynchronous Programming in Rust › Structured Concurrency › Principles of structured concurrency

Some designs work very naturally under structured concurrency (e.g., worker tasks with a single job to complete), while others don't fit so well. Generally these patterns are ones where not being tied to a specific task is a feature, e.g., worker pools or background threads. Even using these patterns, the tasks usually shouldn't outlive the whole program and so there is always one task which can be the parent.
[^start-parent]: This is not actually a hard requirement for structured concurrency. If the temporal scope of a task can be represented in the program and passed between tasks, then a child task can be started by one task but have another as its parent.


Asynchronous Programming in Rust › Structured Concurrency › Principles of structured concurrency › Implementing structured concurrency

The exemplar implementation of structured concurrency is the Python Trio library. Trio is a general purpose library for async programming and IO designed around the concepts of structured concurrency. Trio programs use the `async with` construct to define a lexical scope for spawning tasks. Spawned tasks are associated with a nursery object (which is somewhat like a Scope in Rust). The lifetime of a task is tied to the dynamic temporal scope of its nursery, and in the common case, the lexical scope of an `async with` block. This enforces the parent/child relationship between tasks and thus the tree-invariant of structured concurrency.
Error handling uses Python exceptions which are automatically propagated to parent tasks.

Structured Concurrency
Principles of structured concurrency
Implementing structured concurrency


Asynchronous Programming in Rust › Structured Concurrency › Principles of structured concurrency › Partially structured concurrency

Like many programming techniques, the full benefits of structured concurrency come from *only* using it. If all concurrency is structured, then it makes it much easier to reason about the behaviour of the whole program. However, that has requirements on a language which are not easily met; it is easy enough to do unstructured concurrency in Rust, for example. However, even applying the principles of structured concurrency selectively, or thinking in terms of structured concurrency can be useful.
One can use structured concurrency as a design discipline. When designing a program, always consider and document the parent-child relationships between tasks and ensure that a child task terminates before it's parent. This is usually fairly easy under normal execution, but can be difficult in the face of cancellation and panics.
Another element of structured concurrency which is fairly easy to adopt is to always propagate errors to the parent task. Just like regular error handling, the best thing to do might be to ignore the error, but this should be explicit in the code of the parent task.
Another programming discipline to learn from structured concurrency is to cancel all child tasks in the event of cancelling a parent task. This makes the structural concurrency guarantees much more reliable and makes cancellation in general easier to reason about.

Structured Concurrency
Principles of structured concurrency
Partially structured concurrency


Asynchronous Programming in Rust › Structured Concurrency › Practical structured concurrency with async Rust

Concurrency in Rust (whether async or using threads) is inherently unstructured. Tasks can be arbitrarily spawned, errors and panics on other tasks can be ignored, and cancellation is usually instantaneous and does not propagate to other tasks (see below for why these issues can't be easily solved). However, there are several ways you can get some of the benefits of structured concurrency in your programs:
- Design your programs at a high level in accordance with structured concurrency.
- Stick to structured concurrency idioms where possible (and avoid unstructured idioms).
- Use crates to make structured concurrency more ergonomic and reliable.
One of the trickiest issues with using structured concurrency with Rust is propagating cancellation to child futures/tasks. If you're using futures and composing them concurrently, then this happens naturally if abruptly (dropping a future drops any futures it owns, cancelling them). However, when a task is dropped, there is no opportunity to send a signal to tasks it has spawned (at least not with Tokio[^join_handle]).
The implication of this is that you can only assume a weaker invariant than with 'real' structured concurrency: rather than being able to assume that a parent task is always alive, you can only assume that the parent is always alive unless it has been cancelled or it has panicked. While this is sub-optimal, it can still simplify programming because you never have to handle the case of having no parent to handle some result *under normal execution*.
TODO
- ownership/lifetimes naturally leading to sc
- reasoning about resources
[^join_handle]: The semantics of Tokio's `JoinHandle` is that if the handle is dropped, then the underlying task is 'released' (c.f., dropped), i.e., the result of the child task is not handled by any other task.


Asynchronous Programming in Rust › Structured Concurrency › Practical structured concurrency with async Rust › Applying structured concurrency to the design of async programs

In terms of designing programs, applying structured concurrency has a few implications:
- Organising the concurrency of a program in a tree structure, i.e., thinking in terms of parent and child tasks.
- Temporal scope should follow lexical scope where possible, or in concrete terms a function shouldn't return (including early returns and panics) until any tasks launched in the function are complete.
- Data generally flows from child tasks to parent tasks. Of course, some data will flow from parents to children or in other ways, but primarily, tasks pass the results of their work to their parent tasks for further processing. This includes errors, so parent tasks should handle the errors of their children.
If you're writing a library and want to use structured concurrency (or you want the library to be usable in a concurrent-structured program), then it is important that encapsulation of the library component includes temporal encapsulation. I.e., it doesn't start tasks which keep running beyond the API functions returning.
Since Rust can't enforce the rules of structured concurrency, it's important to be aware of, and to document, in which ways the program (or component) is structured and where it violates the structured concurrency discipline.
One useful compromise pattern is to only allow unstructured concurrency at the highest level of abstraction, and only for tasks spawned from the outer-most functions of the main task (ideally only from the `main` function, but programs often have some setup or configuration code which means that the logical 'top level' of a program is actually a few functions deep). Under such a pattern, a bunch of tasks are spawned from `main`, usually with distinct responsibilities and limited interaction between each other. These tasks might be restarted, new tasks started by any other task, or have a limited lifetime tied to clients or similar, i.e., they are concurrent-unstructured. Within each of these tasks, structured concurrency is rigorously applied.
TODO why is this useful?


Asynchronous Programming in Rust › Structured Concurrency › Practical structured concurrency with async Rust › Applying structured concurrency to the design of async programs

TODO would be great to have a case study here.


Asynchronous Programming in Rust › Structured Concurrency › Practical structured concurrency with async Rust › Structured and unstructured idioms

This subsection covers a grab-bag of idioms which work well with a structured approach to concurrency, and a few which make structuring concurrency more difficult.
The easiest way to follow structured concurrency is to use futures and concurrent composition rather than tasks and spawning. If you need tasks for parallelism, then you will need to use `JoinHandle`s or `JoinSet`s. You must take care that child tasks can clean up properly if the parent task panics or is cancelled. Handles must be checked for errors to ensure errors in child tasks are properly handled.
One way to work around the lack of cancellation propagation is to avoid abruptly cancelling (dropping) any task which may have children. Instead use a signal (e.g., a cancellation token) so that the task can cancel it's children before terminating. Unfortunately this is incompatible with `select`.
To handle shutting down a program (or component), use an explicit shutdown method rather than dropping the component, so that the shutdown function can wait for child tasks to terminate or cancel them (since `drop` cannot be async).
A few idioms do not play well with structured concurrency:
- Spawning tasks without awaiting their completion via a join handle, or dropping those join handles.
- Select or race macros/functions. These are not inherently structured, but since they abruptly cancel futures, it's a common source of unstructured cancellation.
- Worker tasks or pools. For async tasks the overheads of starting/shutting down tasks is so low that there is likely to be very little benefit of using a pool of tasks rather than a pool of 'data', e.g., a connection pool.
- Data with no clear ownership structure - this isn't necessarily in contradiction with structured concurrency, but often leads to design issues.


Asynchronous Programming in Rust › Structured Concurrency › Practical structured concurrency with async Rust › Crates for structured concurrency

TODO
- crates: moro, async-nursery
- futures-concurrency


Asynchronous Programming in Rust › Structured Concurrency › Related topics

This section is not necessary to know to use structured concurrency with async Rust, but is useful context included for the curious.


Asynchronous Programming in Rust › Structured Concurrency › Related topics › Scoped threads

Structured concurrency with Rust threads works pretty well. Although you can't prevent spawning threads with unscoped lifetime, this is easy to avoid. Instead, restrict yourself to using scoped threads, see the `scope` function docs for how. Using scoped threads limits child lifetimes and automatically propagates panics back to the parent thread. The parent thread must check the results of child threads to handle errors though. You can even pass around the `Scope` object like a Trio nursery. Cancellation is not usually an issue for Rust threads, but if you do make use of thread cancellation, you'll have to integrate that with scoped threads manually.
Specific to Rust, scoped threads allow child threads to borrow data from the parent thread, something not possible with concurrent-unstructured threads. This can be very useful and shows how well structured concurrency and Rust-ownership-style resource management can work together.

Structured Concurrency
Related topics
Scoped threads


Asynchronous Programming in Rust › Structured Concurrency › Related topics › Async drop and scoped tasks

In Rust, destructors (`drop`) are used to ensure resources are cleaned up when an object's lifetime ends. Since futures are just objects, their destructor would be an obvious place to ensure cancellation of child futures. However, in an async program it is very often desirable for cleanup actions to be asynchronous (not doing so can block other tasks). Unfortunately Rust does not currently support asynchronous destructors (async drop). There is ongoing work to support them, but it is difficult for a number of reasons, including that an object with an async destructor might be dropped from non-async context, and that since calling `drop` is implicit, there is nowhere to write an explicit `await`.
Given how useful scoped threads are (both in general and for structured concurrency), another good question is why there is no similar construct for async programming ('scoped tasks')? TODO answer this

Structured Concurrency
Related topics
Async drop and scoped tasks


Asynchronous Programming in Rust › Structured Concurrency › Related topics › References

If you're interested, here are some good blog posts for further reading:
- Structured Concurrency
- Tree-structured concurrency

Structured Concurrency
Related topics
References


The Rust Programming Language › The Rust Programming Language

_by Steve Klabnik, Carol Nichols, and Chris Krycho, with contributions from the
Rust Community_
This version of the text assumes you’re using Rust 1.97.0 (released 2026-07-09)
or later with `edition = "2024"` in the *Cargo.toml* file of all projects to
configure them to use Rust 2024 Edition idioms. See the “Installation” section
of Chapter 1 for instructions on installing or
updating Rust, and see Appendix E for information
on editions.
The HTML format is available online at
https://doc.rust-lang.org/stable/book/
and offline with installations of Rust made with `rustup`; run `rustup doc
--book` to open.
Several community [translations] are also available.
This text is available in paperback and ebook format from No Starch
Press.
**🚨 Want a more interactive learning experience? Try out a different version
of the Rust Book, featuring: quizzes, highlighting, visualizations, and
more**: <https://rust-book.cs.brown.edu>


The Rust Programming Language › Foreword

The Rust programming language has come a long way in a few short years, from
its creation and incubation by a small and nascent community of enthusiasts, to
becoming one of the most loved and in-demand programming languages in the
world. Looking back, it was inevitable that the power and promise of Rust would
turn heads and gain a foothold in systems programming. What was not inevitable
was the global growth in interest and innovation that permeated through open
source communities and catalyzed wide-scale adoption across industries.
At this point in time, it is easy to point to the wonderful features that Rust
has to offer to explain this explosion in interest and adoption. Who doesn’t
want memory safety, *and* fast performance, *and* a friendly compiler, *and*
great tooling, among a host of other wonderful features? The Rust language you
see today combines years of research in systems programming with the practical
wisdom of a vibrant and passionate community. This language was designed with
purpose and crafted with care, offering developers a tool that makes it easier
to write safe, fast, and reliable code.
But what makes Rust truly special is its roots in empowering you, the user, to
achieve your goals. This is a language that wants you to succeed, and the
principle of empowerment runs through the core of the community that builds,
maintains, and advocates for this language. Since the previous edition of this
definitive text, Rust has further developed into a truly global and trusted
language. The Rust Project is now robustly supported by the Rust Foundation,
which also invests in key initiatives to ensure that Rust is secure, stable,
and sustainable.


The Rust Programming Language › Foreword

This edition of *The Rust Programming Language* is a comprehensive update,
reflecting the language’s evolution over the years and providing valuable new
information. But it is not just a guide to syntax and libraries—it’s an
invitation to join a community that values quality, performance, and thoughtful
design. Whether you’re a seasoned developer looking to explore Rust for the
first time or an experienced Rustacean looking to refine your skills, this
edition offers something for everyone.
The Rust journey has been one of collaboration, learning, and iteration. The
growth of the language and its ecosystem is a direct reflection of the vibrant,
diverse community behind it. The contributions of thousands of developers, from
core language designers to casual contributors, are what make Rust such a
unique and powerful tool. By picking up this book, you’re not just learning a
new programming language—you’re joining a movement to make software better,
safer, and more enjoyable to work with.
Welcome to the Rust community!
- Bec Rumbul, Executive Director of the Rust Foundation


The Rust Programming Language › Introduction

Note: This edition of the book is the same as The Rust Programming
Language available in print and ebook format from No Starch
Press.
Welcome to _The Rust Programming Language_, an introductory book about Rust.
The Rust programming language helps you write faster, more reliable software.
High-level ergonomics and low-level control are often at odds in programming
language design; Rust challenges that conflict. Through balancing powerful
technical capacity and a great developer experience, Rust gives you the option
to control low-level details (such as memory usage) without all the hassle
traditionally associated with such control.


The Rust Programming Language › Introduction › Who Rust Is For

Rust is ideal for many people for a variety of reasons. Let’s look at a few of
the most important groups.


The Rust Programming Language › Introduction › Who Rust Is For › Teams of Developers

Rust is proving to be a productive tool for collaborating among large teams of
developers with varying levels of systems programming knowledge. Low-level code
is prone to various subtle bugs, which in most other languages can only be
caught through extensive testing and careful code review by experienced
developers. In Rust, the compiler plays a gatekeeper role by refusing to
compile code with these elusive bugs, including concurrency bugs. By working
alongside the compiler, the team can spend its time focusing on the program’s
logic rather than chasing down bugs.
Rust also brings contemporary developer tools to the systems programming world:
- Cargo, the included dependency manager and build tool, makes adding,
  compiling, and managing dependencies painless and consistent across the Rust
  ecosystem.
- The `rustfmt` formatting tool ensures a consistent coding style across
  developers.
- The Rust Language Server powers integrated development environment (IDE)
  integration for code completion and inline error messages.
By using these and other tools in the Rust ecosystem, developers can be
productive while writing systems-level code.

Introduction
Who Rust Is For
Teams of Developers


The Rust Programming Language › Introduction › Who Rust Is For › Students

Rust is for students and those who are interested in learning about systems
concepts. Using Rust, many people have learned about topics like operating
systems development. The community is very welcoming and happy to answer
students’ questions. Through efforts such as this book, the Rust teams want to
make systems concepts more accessible to more people, especially those new to
programming.


The Rust Programming Language › Introduction › Who Rust Is For › Companies

Hundreds of companies, large and small, use Rust in production for a variety of
tasks, including command line tools, web services, DevOps tooling, embedded
devices, audio and video analysis and transcoding, cryptocurrencies,
bioinformatics, search engines, Internet of Things applications, machine
learning, and even major parts of the Firefox web browser.


The Rust Programming Language › Introduction › Who Rust Is For › Open Source Developers

Rust is for people who want to build the Rust programming language, community,
developer tools, and libraries. We’d love to have you contribute to the Rust
language.

Introduction
Who Rust Is For
Open Source Developers


The Rust Programming Language › Introduction › Who Rust Is For › People Who Value Speed and Stability

Rust is for people who crave speed and stability in a language. By speed, we
mean both how quickly Rust code can run and the speed at which Rust lets you
write programs. The Rust compiler’s checks ensure stability through feature
additions and refactoring. This is in contrast to the brittle legacy code in
languages without these checks, which developers are often afraid to modify. By
striving for zero-cost abstractions—higher-level features that compile to
lower-level code as fast as code written manually—Rust endeavors to make safe
code be fast code as well.
The Rust language hopes to support many other users as well; those mentioned
here are merely some of the biggest stakeholders. Overall, Rust’s greatest
ambition is to eliminate the trade-offs that programmers have accepted for
decades by providing safety _and_ productivity, speed _and_ ergonomics. Give
Rust a try, and see if its choices work for you.

Introduction
Who Rust Is For
People Who Value Speed and Stability


The Rust Programming Language › Introduction › Who This Book Is For

This book assumes that you’ve written code in another programming language, but
it doesn’t make any assumptions about which one. We’ve tried to make the
material broadly accessible to those from a wide variety of programming
backgrounds. We don’t spend a lot of time talking about what programming _is_
or how to think about it. If you’re entirely new to programming, you would be
better served by reading a book that specifically provides an introduction to
programming.


The Rust Programming Language › Introduction › How to Use This Book

In general, this book assumes that you’re reading it in sequence from front to
back. Later chapters build on concepts in earlier chapters, and earlier
chapters might not delve into details on a particular topic but will revisit
the topic in a later chapter.
You’ll find two kinds of chapters in this book: concept chapters and project
chapters. In concept chapters, you’ll learn about an aspect of Rust. In project
chapters, we’ll build small programs together, applying what you’ve learned so
far. Chapter 2, Chapter 12, and Chapter 21 are project chapters; the rest are
concept chapters.
**Chapter 1** explains how to install Rust, how to write a “Hello, world!”
program, and how to use Cargo, Rust’s package manager and build tool. **Chapter
2** is a hands-on introduction to writing a program in Rust, having you build
up a number-guessing game. Here, we cover concepts at a high level, and later
chapters will provide additional detail. If you want to get your hands dirty
right away, Chapter 2 is the place for that. If you’re a particularly
meticulous learner who prefers to learn every detail before moving on to the
next, you might want to skip Chapter 2 and go straight to **Chapter 3**, which
covers Rust features that are similar to those of other programming languages;
then, you can return to Chapter 2 when you’d like to work on a project applying
the details you’ve learned.
In **Chapter 4**, you’ll learn about Rust’s ownership system. **Chapter 5**
discusses structs and methods. **Chapter 6** covers enums, `match` expressions,
and the `if let` and `let...else` control flow constructs. You’ll use structs
and enums to make custom types.


The Rust Programming Language › Introduction › How to Use This Book

In **Chapter 7**, you’ll learn about Rust’s module system and about privacy
rules for organizing your code and its public application programming interface
(API). **Chapter 8** discusses some common collection data structures that the
standard library provides: vectors, strings, and hash maps. **Chapter 9**
explores Rust’s error-handling philosophy and techniques.
**Chapter 10** digs into generics, traits, and lifetimes, which give you the
power to define code that applies to multiple types. **Chapter 11** is all
about testing, which even with Rust’s safety guarantees is necessary to ensure
that your program’s logic is correct. In **Chapter 12**, we’ll build our own
implementation of a subset of functionality from the `grep` command line tool
that searches for text within files. For this, we’ll use many of the concepts
we discussed in the previous chapters.
**Chapter 13** explores closures and iterators: features of Rust that come from
functional programming languages. In **Chapter 14**, we’ll examine Cargo in
more depth and talk about best practices for sharing your libraries with
others. **Chapter 15** discusses smart pointers that the standard library
provides and the traits that enable their functionality.
In **Chapter 16**, we’ll walk through different models of concurrent
programming and talk about how Rust helps you program in multiple threads
fearlessly. In **Chapter 17**, we build on that by exploring Rust’s async and
await syntax, along with tasks, futures, and streams, and the lightweight
concurrency model they enable.


The Rust Programming Language › Introduction › How to Use This Book

**Chapter 18** looks at how Rust idioms compare to object-oriented programming
principles you might be familiar with. **Chapter 19** is a reference on
patterns and pattern matching, which are powerful ways of expressing ideas
throughout Rust programs. **Chapter 20** contains a smorgasbord of advanced
topics of interest, including unsafe Rust, macros, and more about lifetimes,
traits, types, functions, and closures.
In **Chapter 21**, we’ll complete a project in which we’ll implement a
low-level multithreaded web server!
Finally, some appendixes contain useful information about the language in a
more reference-like format. **Appendix A** covers Rust’s keywords, **Appendix
B** covers Rust’s operators and symbols, **Appendix C** covers derivable traits
provided by the standard library, **Appendix D** covers some useful development
tools, and **Appendix E** explains Rust editions. In **Appendix F**, you can
find translations of the book, and in **Appendix G** we’ll cover how Rust is
made and what nightly Rust is.
There is no wrong way to read this book: If you want to skip ahead, go for it!
You might have to jump back to earlier chapters if you experience any
confusion. But do whatever works for you.