async-rustlisted
Install: claude install-skill rewrite-rs/skills
# Async Rust
Async Rust fails in three places: an executor thread that gets blocked, a guard
held across an await point, and a future dropped mid-operation. This skill
governs *correctness under concurrency and cancellation* — it does not decide
whether the code should be async in the first place.
## Async is not free concurrency
An `async fn` yields a future that does nothing until polled. Concurrency comes
from the runtime and from combining futures — `join!`, `select!`, `spawn` — not
from the `async` keyword:
```rust,ignore
// Serial: the second fetch starts only after the first completes.
let a = fetch_user(id).await;
let b = fetch_orders(id).await;
// Concurrent: both futures are polled at the same time.
let (a, b) = tokio::join!(fetch_user(id), fetch_orders(id));
```
Every `.await` in a function adds to the size of the generated future, and a
large future is copied on every move — into `Box::pin`, into a `JoinSet`.
Many awaits and large locals mean kilobytes; box the inner future or split
the function once a profile says the moves matter.
## Runtime choice, once, at the top
Pick a runtime, in the overwhelming majority of cases `tokio`, deliberately.
The library rules: stay runtime-agnostic if you can, feature-gate the
integration if you cannot, and never start a runtime inside a library
function (`#[tokio::main]` belongs in a binary or test; a `Runtime::block_on`
there hands the consumer a second, conflicting executor).
## Blocking work in an async context
A C