← ClaudeAtlas

async-rustlisted

Write correct async Rust — runtime choice, Send and Sync bounds, cancellation safety, blocking work inside async contexts, and shared state across tasks. Use when writing or reviewing async code, when a future is held across an await point, when the user hits a Send bound error on a spawned task, when a runtime stalls or deadlocks, or when the user asks about tokio, select!, or spawn_blocking.
rewrite-rs/skills · ★ 2 · Code & Development · score 73
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