Rust — Reference

Source: https://doc.rust-lang.org/book/

Rust

  • Created: 2010 by Graydon Hoare at Mozilla; 1.0 released 2015-05-15
  • Latest stable: Rust 1.95.0 (2026-04-16); 6-week release cycle
  • Paradigms: multi-paradigm — imperative, functional, generic, concurrent, low-level systems
  • Typing: static, strong, nominal, with Hindley-Milner-flavored inference; traits (type classes); ADTs (enum/struct)
  • Memory: borrow-checked (ownership + lifetimes, no GC); manual via unsafe raw pointers
  • Compilation: AOT to native via LLVM; monomorphized generics; produces single static binary by default
  • Primary domains: systems, embedded, WebAssembly, CLI tools, blockchain, game/graphics engines, databases, browser engines (Servo, Stylo), OS development (Linux kernel, Windows components)
  • Official docs: https://doc.rust-lang.org/

1. At a glance

  • Stewarded by the Rust Foundation (independent non-profit since 2021, with Platinum members Amazon/Google/Microsoft/Meta/Huawei/Mozilla); technical governance via Project teams (compiler, lang, libs, infra, dev-tools, release, moderation) + RFC process on GitHub.
  • One main implementation: rustc (LLVM-based, written in Rust, with the codegen backend pluggable). gccrs (GCC frontend, separately implemented — reached self-hosting feature parity goals in GCC 15) and rustc_codegen_cranelift (faster debug builds, no LLVM dep) emerging. rustc_codegen_gcc uses libgccjit for backend (parity work ongoing).
  • Editions: 2015, 2018, 2021, 2024 (default since Rust 1.85, Feb 2025) — opt-in syntactic/semantic shifts; libraries from different editions interoperate freely. edition = "2024" in Cargo.toml.
  • Compiler messages and tooling (cargo, rustup, clippy, rust-analyzer) are best-in-class — diagnostic spans, hint suggestions, machine-applicable fixes via --fix.
  • 6-week release cadence (same as Chrome/Firefox); LTS-like patterns through company-level toolchain pinning (Google/AWS/Microsoft typically lag 2-3 releases).
  • Rust Survey 2025 (annual): ~95% of users use stable, ~30% nightly; Tokio + serde + clap dominate; “compile times” remains top pain point.

2. Getting started

  • Install: rustup is the official toolchain manager: curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh (or winget install Rustlang.Rustup). Configures cargo + rustc + rust-std + rust-docs + clippy + rustfmt per channel.

  • Version manager: rustup itself: rustup install stable|beta|nightly, rustup default stable, rustup target add wasm32-unknown-unknown, rustup component add rust-src. Override per-dir with rust-toolchain.toml:

    [toolchain]
    channel = "1.83.0"
    components = ["rustfmt", "clippy", "rust-src"]
    targets = ["wasm32-wasip1", "x86_64-unknown-linux-musl"]
  • Hello, world:

    fn main() { println!("Hello, world!"); }

    Create + run: cargo new hello && cd hello && cargo run. Cargo.toml generated:

    [package]
    name = "hello"
    version = "0.1.0"
    edition = "2024"
    rust-version = "1.85"
     
    [dependencies]
  • Project layout: Cargo.toml (manifest) + Cargo.lock (locked deps; commit for binaries, optional for libs); src/main.rs (binary entry point) or src/lib.rs (library entry point); src/bin/<name>.rs for additional binaries; tests/ (integration tests, each file its own crate), benches/ (Criterion lives here), examples/ (runnable with cargo run --example foo). Workspaces (top-level Cargo.toml with [workspace]) for multi-crate monorepos — share target/ directory and dependency graph.

  • Build tool: cargo is everything: cargo build, run, test (or cargo nextest run), bench, doc, publish, add, update, tree, clippy, fmt, check (type-check without codegen — fastest feedback), expand (macro output), audit, deny, machete. Crates from crates.io (108k+ as of 2026); private registries via Artifactory, Cloudsmith, Shipyard, JFrog. Workspace-level [workspace.dependencies] and [workspace.lints] (1.74+) keep monorepos consistent.

  • REPL/playground: Rust Playground (https://play.rust-lang.org/) — share with shortlink, run on stable/beta/nightly, see ASM/MIR/LLVM-IR output. evcxr (Jupyter kernel + REPL — interactive Rust with reloadable cells, used by data-science folks). miri playground for visualizing UB. rust.godbolt.org (Compiler Explorer) for cross-version disassembly.

3. Basics

  • Primitives: bool, char (4-byte Unicode scalar value, not a byte), signed/unsigned ints i8..i128/isize, u8..u128/usize, f32/f64, () unit type, ! never type (in return/expr positions). Literals: 0x, 0b, 0o, _ separators (1_000_000), suffixes (42u32, 3.14f64), byte literals b'x', raw byte strings br"...".
  • Variables: let x = 1; (immutable by default), let mut x, const FOO: u32 = 42; (compile-time, inlined at each use site), static FOO: u32 = 42; (single memory location). Shadowing allowed (let x = x + 1; re-binds, can change type). Block-scoped, expression-oriented (last expression without ; returns). let _ = expr to explicitly discard.
  • Control flow: if/else (an expression — let x = if cond { 1 } else { 2 };), match (exhaustive pattern-matching, the workhorse — compiler checks all variants covered), loop (infinite, can break value), while, while let Some(x) = it.next(), for x in iter, break/continue with labels ('outer: loop { ... break 'outer; }), if let / let else (1.65+) for one-arm match. Patterns: literal, range, struct, enum, tuple, slice ([head, .., tail]), or-patterns (A | B), guards (Some(x) if x > 5), bindings (x @ 1..=5).
  • Functions: fn f(x: i32) -> i32 { x + 1 }. No default args / no overloading (use builder pattern or Option<T>). Closures |x| x + 1 (auto-traits Fn/FnMut/FnOnce determined by capture mode). Generics + traits substitute for overloading. First-class via fn pointers (zero-cost, no captures), closures (impl Fn, may capture), dyn Trait (vtable, type-erased). Async closures (async |x| { ... }) stable in 1.85+.
  • Strings: &str (string slice, UTF-8, fat pointer = ptr + len) and owning String (heap, growable Vec guaranteed UTF-8). Format with format!("{x}") / println!; raw strings r"...", r#"..."# (any number of # to disambiguate from " in content). No interpolation outside macros. String::from, .to_string(), .to_owned(), .into() all convert &str → String. OsString/OsStr for OS-native (Windows UTF-16, Unix bytes); Path/PathBuf for filesystem paths; CString/CStr for NUL-terminated C interop.
  • Collections: arrays [T; N] (stack-allocated fixed size), slices &[T]/&mut [T] (fat pointer view), Vec<T> (heap-allocated growable), HashMap<K, V> (SipHash 1-3 default — DoS resistant but slower; swap for ahash/fxhash if input is trusted) / BTreeMap<K, V> (ordered, B-tree, better cache behavior than tree map), HashSet<T> / BTreeSet<T>, VecDeque<T> (ring buffer), BinaryHeap<T> (max-heap by default), tuples (T1, T2), Option<T> (sum type for nullability — no null pointers), Result<T, E> (sum type for fallible operations). Smart pointers: Box<T> (single-owner heap), Rc<T> (single-threaded ref-counted), Arc<T> (thread-safe ref-counted), Cell<T> (interior mutability for Copy types), RefCell<T> (runtime borrow-checked interior mutability), Mutex<T>, RwLock<T>, OnceLock<T>/OnceCell<T> (1.70+ — lazy init), LazyLock<T>/LazyCell<T> (1.80+).

4. Intermediate

  • Generics & traits: fn f<T: Trait>(x: T) or where T: Trait. Trait objects dyn Trait (vtable; only object-safe traits — no generic methods, no Self returns by value). Associated types (type Item; in trait), Generic Associated Types (GATs, stable 1.65 — type Item<'a>; for lifetime-parameterized return types from a trait). Higher-ranked trait bounds for<'a> Fn(&'a T) -> .... Lifetimes are part of types: &'a str, fn f<'a>(x: &'a str) -> &'a str. Variance is computed structurally — &'a T is covariant in 'a, &'a mut T is invariant. Default type parameters <T = String>. Opaque types via impl Trait in arg or return position.
  • Modules/packages: crate = compilation unit; module tree via mod foo; (loads from foo.rs or foo/mod.rs) or mod foo { ... } (inline), pub/pub(crate)/pub(super)/pub(in crate::path) for graduated visibility. Cargo packages contain one or more crates (one library + multiple binaries + tests + benches + examples) and are published to crates.io. Workspaces ([workspace] in top-level Cargo.toml) share target/ and Cargo.lock.
  • Error handling: Result<T, E> + ? operator for propagation (auto-converts via From<E1> for E2). Option<T> for absence. panic! for unrecoverable bugs (can unwind or abort based on panic = profile). Libraries use thiserror (derive macro for Error + Display); apps use anyhow (anyhow::Result<T> = Result<T, anyhow::Error> + .context(...) for stack-like attached info); miette for rustc-quality diagnostics; color-eyre for prettier panic backtraces; eyre as anyhow alternative with custom reports.
  • Concurrency: std::thread::spawn + scoped threads (std::thread::scope, 1.63 — can borrow from caller’s stack), channels (std::sync::mpsc — single-producer single-consumer-ish; for mpmc use crossbeam-channel or flume or tokio::sync::broadcast), Mutex<T>/RwLock<T>/Arc<T>, std::sync::atomic (with Ordering::{Relaxed, Acquire, Release, AcqRel, SeqCst}), std::sync::Barrier, OnceLock/LazyLock, parking_lot crate (faster, smaller Mutex/RwLock). Async: async fn + .await (compiler desugars to state machines implementing Future); requires a runtime — Tokio is dominant (multi-threaded work-stealing); smol, glommio, monoio (thread-per-core, io_uring on Linux). Async sync primitives: tokio::sync::Mutex/RwLock/Semaphore/Notify/watch/broadcast/mpsc/oneshot.
  • I/O & networking: std::fs, std::io (Read/Write traits + BufReader/BufWriter — buffer your I/O!), std::net (TCP/UDP), std::process. Async I/O via Tokio (tokio::fs, tokio::net::TcpListener, tokio::io::AsyncReadExt/AsyncWriteExt). For HTTP client: reqwest (most popular), ureq (sync, no Tokio), hyper (low-level — what reqwest is built on). Server-side: hyper + axum/actix-web.
  • Stdlib highlights: Iterator (the most powerful trait — map/filter/collect/fold/scan/flat_map/zip/chain/take/skip/step_by/enumerate/peekable/fuse/inspect/by_ref + 80 more, all lazy until terminal collect/sum/count/fold), From/Into (infallible conversion)/TryFrom/TryInto (fallible), Display/Debug ({} vs {:?}), Default, Clone (explicit deep copy)/Copy (memcpy semantics), Drop (destructor), Deref/DerefMut (smart pointer auto-coercion), IntoIterator / FromIterator, Eq/Ord/Hash. std::collections, std::sync, std::env, std::process, std::time (Instant, Duration), std::path (Path/PathBuf), std::ffi (CStr/CString/OsStr/OsString).

5. Advanced

  • Memory & ownership: every value has exactly one owner; borrows are either one mutable or many shared (the borrow-check rule); lifetimes encode reference validity. Drop trait runs on scope exit. No GC, no runtime memory tracking. NLL (Non-Lexical Lifetimes) makes borrows scope-tight. Polonius (next-gen borrow checker, in nightly + opt-in 1.83+) accepts strictly more programs — particularly around conditional borrows; targeting stabilization 2026-27.
  • Concurrency deep dive: Send (transferable across threads) + Sync (shareable across threads) auto-traits enforce thread safety at compile time. Pin<T>/Unpin for self-referential types (used by async). Lock-free via std::sync::atomic. Async runtimes: Tokio’s work-stealing scheduler, scoped tasks, structured concurrency (cancellation, JoinSet, task::AbortHandle). std::thread::scope (1.63+) gives borrow-checked thread spawning that can’t outlive borrows.
  • FFI/interop: extern "C" fn for C ABI; bindgen generates Rust bindings from C headers, cbindgen generates C headers from Rust. cxx (David Tolnay) for C++ interop (safe bidirectional) — production at Mozilla (Servo, Firefox), Google (Chromium), in the Linux kernel. autocxx (Google) extends cxx with auto-generation. pyo3 + maturin for Python (used by Pydantic, Polars, ruff). napi-rs for Node.js. uniffi for cross-lang bindings (Mozilla; generates Kotlin, Swift, Python, Ruby from a single UDL). diplomat for FFI-friendly idiomatic APIs across many targets. WASM: wasm-bindgen + wasm-pack for browsers; wasi-sdk and cargo-component for the Component Model + WIT (WebAssembly Interface Types).
  • Reflection: none at runtime (no RTTI). Substitute: std::any::TypeId/Any for downcasting, Debug for printing, derive macros for compile-time codegen. bevy_reflect provides runtime reflection in the Bevy ecosystem; facet (Amos) explores a general-purpose reflection-without-derive design.
  • Performance tooling: cargo bench + Criterion (statistical benchmarks with regression detection), cargo flamegraph, samply (cross-platform sampling profiler, Firefox Profiler UI), perf, valgrind/cachegrind, cargo-llvm-lines (codegen size — find generic instantiation explosions), cargo-bloat (binary size — what’s taking space), hyperfine (CLI bench), heaptrack/bytehound (memory profilers), cargo-nextest (parallel test runner, 50-60% faster than cargo test), cargo-mutants (mutation testing), cargo-fuzz + libFuzzer + afl.rs (fuzzing). Compile flags: --release, RUSTFLAGS=-C target-cpu=native, lto = "fat" or "thin", codegen-units = 1 in Cargo.toml (slower compile, faster code), panic = "abort" (smaller binary, no unwinding tables). PGO + BOLT supported via cargo-pgo. cargo-flamegraph for one-line CPU flamegraphs.
  • Compile-time tooling: cargo-sweep (clean old artifacts), sccache (Mozilla, distributed compile cache), cargo-chef (Docker layer caching), cranelift backend (-Zcodegen-backend=cranelift, nightly) — 30% faster debug builds, used by Cloudflare. Watch crate count: each new dep adds to incremental compile time.

6. God mode

  • Macros: declarative macro_rules! foo { ($x:expr) => { ... } } — pattern-matched token transformations; procedural macros — derive, attribute, function-like; receive TokenStream, return TokenStream. Built with syn (parser) + quote (quote! { ... } template) + proc-macro2 (cross-version TokenStream). Inspect output with cargo expand. Famous proc-macros: #[derive(Serialize, Deserialize)] (serde), #[tokio::main], #[wasm_bindgen], #[sqlx::query!] (compile-time SQL checks), #[bitflags].
  • unsafe Rust: unlocks raw pointers (*const T/*mut T), unchecked indexing, calling unsafe fn, mutating statics, implementing unsafe traits, dereferencing pointers, mem::transmute. The Rustonomicon is the spec; miri interprets MIR to detect UB in unsafe code (out-of-bounds, use-after-free, invalid transmute, data races, alignment violations). Run with cargo +nightly miri test. cargo-careful runs with extra checks.
  • Lifetimes deep: variance (covariant/contravariant/invariant), HRTBs (for<'a> ...), 'static, lifetime elision rules, PhantomData<T> for declaring variance/drop semantics on zero-sized types. PhantomPinned for explicit !Unpin.
  • Zero-sized types (ZSTs): unit (), empty structs, marker types — take 0 bytes; Vec<()> is just a length counter. Used heavily for type-state patterns (Door<Open> / Door<Closed>), unit-struct policy parameters, marker traits.
  • Pin/Unpin and async internals: Future::poll returns Poll<T>; async fns desugar to a state-machine struct with each .await becoming a state. Pin enforces self-referential safety. Wakers + Tasks + Executors form the runtime. async fn in traits stable since 1.75 (static dispatch only); RPITIT (return-position impl Trait in traits) stable 1.75; dyn async traits require crates like async-trait or the boxed-future workaround. Async closures stable in 1.85+ (async |x| { ... } syntax).
  • no_std: disable libstd for embedded / kernels; opt into alloc (for Box/Vec/String against a global allocator) or stay pure (core only). Targets like thumbv7em-none-eabihf for Cortex-M, riscv32imac-unknown-none-elf for RISC-V, x86_64-unknown-uefi for UEFI apps.
  • Custom allocators: #[global_allocator] static A: MyAlloc = MyAlloc; (e.g., mimalloc, jemallocator, tikv-jemallocator, snmalloc-rs); allocator API for per-collection allocators (Allocator trait, stable as allocator_api2 shim).
  • MIR inspection: cargo +nightly rustc -- -Zunpretty=mir (or =hir, =hir-tree, =ast). Cranelift backend for fast debug. cargo asm / cargo-show-asm to view generated assembly per function.
  • Embedded HAL: embedded-hal 1.0 (stable Jan 2024) crate trait ecosystem — drivers written once work across vendors; RTIC (Real-Time Interrupt-driven Concurrency) and Embassy async runtimes for microcontrollers; probe-rs for flashing/debugging with cargo-embed/cargo-flash; defmt for low-overhead logging; vendor HALs: esp-hal (Espressif official, supersedes esp-rs), nrf-hal, rp-hal (Raspberry Pi RP2040), stm32-rs.
  • Cargo build scripts (build.rs) — compile C dependencies via cc crate, generate code, set link flags, conditionally compile via cargo:rustc-cfg=. Custom Cargo subcommands: any binary named cargo-foo on PATH becomes cargo foo.
  • Specialization (unstable nightly), const generics (stable + feature(generic_const_exprs) for arithmetic), const evaluation, GATs (stable 1.65), async traits in traits (1.75 stable for static dispatch, dyn dispatch via crate). let chains stabilized 1.83. let-else stable 1.65. Never type ! partially stable (function returns, exhaustive match arms).
  • Rust for Linux: merged in kernel 6.1 (Dec 2022), driver support growing — Apple AGX GPU driver, Nova Nvidia driver in nightly, Asahi Linux contributions; some maintainer drama 2024-25 around the C/Rust boundary. By 2026, Rust-written drivers are routine in mainline.

Trait & type pattern catalog

// Newtype for type safety
struct UserId(u64);
struct OrderId(u64);
fn lookup(u: UserId, o: OrderId) { /* can't accidentally swap */ }
 
// Type-state pattern with PhantomData
use std::marker::PhantomData;
struct Door<State>(PhantomData<State>);
struct Open; struct Closed;
impl Door<Closed> { fn open(self) -> Door<Open> { Door(PhantomData) } }
impl Door<Open>   { fn close(self) -> Door<Closed> { Door(PhantomData) } }
 
// Builder pattern
#[derive(Default)]
struct ServerBuilder { port: Option<u16>, host: Option<String> }
impl ServerBuilder {
    fn port(mut self, p: u16) -> Self { self.port = Some(p); self }
    fn host(mut self, h: impl Into<String>) -> Self { self.host = Some(h.into()); self }
    fn build(self) -> Server {
        Server { port: self.port.unwrap_or(8080), host: self.host.unwrap_or_else(|| "0.0.0.0".into()) }
    }
}
 
// Extension trait
trait StrExt { fn shout(&self) -> String; }
impl StrExt for str { fn shout(&self) -> String { self.to_uppercase() + "!" } }
 
// Sealed trait (prevent external impls)
mod sealed { pub trait Sealed {} }
pub trait MyTrait: sealed::Sealed { /* ... */ }
impl sealed::Sealed for MyType {}
impl MyTrait for MyType {}
 
// Visitor pattern with enum + match
enum Shape { Circle(f64), Square(f64), Rect(f64, f64) }
impl Shape {
    fn area(&self) -> f64 {
        match self {
            Self::Circle(r) => std::f64::consts::PI * r * r,
            Self::Square(s) => s * s,
            Self::Rect(w, h) => w * h,
        }
    }
}

7. Idioms & style

  • Naming: snake_case for vars, fns, modules, crates; PascalCase for types, traits, enum variants; SCREAMING_SNAKE_CASE for consts/statics; lifetime params short ('a, 'de, 'tcx in rustc itself).
  • Formatter: rustfmt (cargo fmt) — universally applied; rustfmt.toml for project tweaks; near-zero configurable variance. Linter: clippy (cargo clippy) with 700+ opinionated lints across correctness, suspicious, style, complexity, perf, pedantic, nursery, cargo; CI gate (cargo clippy -- -D warnings).
  • Idiomatic Rust: prefer iterators over indexed loops (map/filter/collect); use ? for error propagation; return Result<_, E> not panic; build small types and impl traits on them; favor borrowing over cloning; newtype wrappers for type safety (struct UserId(u64)); trait-based extension over inheritance; From/Into for conversion; use derive for Debug/Clone/PartialEq; let the compiler guide you. API guidelines (rust-lang.github.io/api-guidelines/) are the canonical doc.
  • Error patterns: thiserror for libraries (derives Error + Display), anyhow for apps (anyhow::Result<T> + .context("loading config")), miette for fancy diagnostic-style errors (powers rustc-quality error reports in CLIs like oxc, dprint).
  • Reviewers look for: unnecessary .clone(), unwrap()/expect() in non-test code, missing #[must_use], lifetime elision opportunities, missing Send/Sync bounds, unsafe without // SAFETY: comments, public API ergonomics (accept impl AsRef<Path> not &Path), missing #[non_exhaustive] on enums that may grow, pub use re-exports for clean module surface, missing #[derive(Default)] where sensible.

8. Ecosystem

  • Web (server): Axum (Tokio team, dominant in 2024-26), Actix Web (still fast, less idiomatic), Rocket, Warp, Poem, Loco (Rails-inspired), Salvo.
  • Web (frontend, WASM): Leptos (fine-grained, SSR + hydration), Dioxus (React-like, multi-platform), Yew, Sycamore, Sauron, Maud / Askama (HTML templating).
  • GUI (native): Tauri 2 (lightweight Electron alternative, web frontend + Rust backend, multi-platform incl. mobile), egui (immediate-mode, GPU-accelerated, used by Rerun + Embark), iced (Elm-architecture, native), Slint (declarative UI for desktop/embedded), gtk4-rs, Dioxus Desktop, Druid (deprecated).
  • Async runtimes: Tokio (dominant, multi-threaded work-stealing), smol (single-binary, simple), async-std (deprecated / unmaintained), glommio (thread-per-core, io_uring, Datadog), monoio (Bytedance, thread-per-core, io_uring), bastion (actor model), embassy (no_std async for embedded).
  • CLI: clap (the standard, both derive + builder), argh (Google, simpler), structopt (deprecated, use clap-derive). Output: indicatif (progress bars), ratatui (TUI framework, fork of tui-rs), crossterm (cross-platform terminal), owo-colors, anstyle, dialoguer (interactive prompts), inquire.
  • Data/serialization: serde + serde_json / toml / bincode (binary, compact) / rmp-serde (MessagePack) / postcard (no_std friendly) / ciborium (CBOR) / ron (Rust-native human-readable). Fast JSON: simd-json (Cloudflare port), sonic-rs (Bytedance, even faster), serde-json-core (no_std). Database: sqlx (compile-time query checking), diesel (sync ORM, fastest), sea-orm (async ORM), rusqlite, tokio-postgres, mongodb-rust.
  • Game/graphics: Bevy (ECS-based game engine, fast-moving), wgpu (cross-platform GPU API, runs on WebGPU/Vulkan/Metal/DX12, used by Firefox), ggez, macroquad (small/simple), rend3, Fyrox, Ambient.
  • Embedded: embassy (async no_std), RTIC (interrupt-driven), embedded-hal 1.0 (stable), defmt (microscopic logging), probe-rs (cargo-embed, cargo-flash), postcard (serialization), heapless (stack-only collections).
  • Logging/tracing: tracing (Tokio team, structured + spans, dominant), log + env_logger (legacy simple), slog (older structured), flexi_logger, tracing-subscriber (formatter/filter layer), opentelemetry-rust (OTLP export).
  • Testing: stdlib #[test] + cargo test (or cargo nextest run for 60% faster runs); proptest / quickcheck (property-based), criterion (benchmarks with regression detection), insta (snapshot testing, Armin Ronacher), mockall, rstest (parameterized + fixtures), fake (data generation), wiremock (HTTP mocking).
  • Fuzzing: cargo-fuzz + libFuzzer, afl.rs, honggfuzz-rs. Used at scale by Cloudflare, Mozilla, Microsoft (OSS-Fuzz integration).
  • Doc tools: cargo doc + rustdoc (HTML, doctest — examples in docs run as tests); mdBook for long-form (used by the Rust book itself). Auto-published on docs.rs.
  • Quality / security: clippy (idiom lints), cargo-audit (RustSec advisory DB), cargo-deny (license + advisory + dupe-version gates), cargo-machete (find unused deps), cargo-msrv (find minimum supported Rust version), cargo-tarpaulin (coverage, Linux), grcov (cross-platform coverage), cargo-llvm-cov.
  • Notable users: Linux kernel (since 6.1 — drivers including Apple GPU, network, Nova nvidia in nightly), Microsoft (Windows components in win32k.sys/DWriteCore, Azure CBL-Mariner, M365 cores), Google (Android Bluetooth + Crosvm + Fuchsia core), Apple (parts of Darwin), Mozilla (Servo revival 2024 under Linux Foundation, Stylo), Cloudflare (Pingora proxy — replaced NGINX, workerd, Quiche QUIC), Discord, Dropbox (Magic Pocket), Meta (source control Sapling), Amazon (Firecracker, Bottlerocket, Lambda components), Figma (multiplayer server), 1Password, Postman (Insomnia successor), Vercel (turbo + turbopack), npm registry, Asahi Linux.

Async Rust deep dive

Async Rust is the most powerful and most controversial feature of the language. Key concepts:

  • async fn desugars to fn() -> impl Future<Output = T> — the function body becomes a state machine struct that implements Future.
  • .await is a suspension point — the executor calls Future::poll, and if the future returns Poll::Pending, the current task yields back to the runtime.
  • No async runtime in std — Rust ships the Future trait and async/await syntax but no executor. Pick Tokio (default for most), smol, glommio, monoio, embassy (no_std embedded).
  • Send/Sync infect everything — async functions inherit auto-traits from their captures. Hold a Rc<T> across an .await and your future is !Send, breaking Tokio’s multi-threaded runtime. Use Arc<T> instead.
  • Pinning ensures self-referential async state machines don’t move after polling starts. Box::pin(fut) is the heap-allocated escape hatch; tokio::pin!(fut) for stack-pinning a local.
  • Cancellation: dropping a future cancels it (no kill -9-style coercion). Cooperative — the future stops being polled. Use tokio::select! { _ = fut => ..., _ = ctx.cancelled() => ... } for race / cancel.
  • async fn in traits (1.75+) works for static dispatch via impl Trait-in-return-position. For dynamic dispatch (dyn AsyncTrait), use async-trait crate or manual boxed-future. Full stabilization landed 1.86.
  • Common foot-guns: blocking inside async (std::thread::sleep instead of tokio::time::sleep), holding sync mutexes across .await (use tokio::sync::Mutex), spawning detached tasks that outlive the runtime (handles must be awaited or detached deliberately).
use tokio::time::{sleep, Duration};
 
#[tokio::main]
async fn main() {
    let h1 = tokio::spawn(async { sleep(Duration::from_millis(100)).await; 1 });
    let h2 = tokio::spawn(async { sleep(Duration::from_millis(200)).await; 2 });
    let (r1, r2) = tokio::join!(h1, h2);
    println!("{} {}", r1.unwrap(), r2.unwrap());
}

Memory + ownership cookbook

// Borrow split — let two non-overlapping fields be borrowed mutably
struct Pair { a: String, b: String }
fn use_both(p: &mut Pair) {
    let Pair { a, b } = p;     // structural pattern split borrows by field
    a.push('!'); b.push('?');
}
 
// Cow<'_, T> — clone-on-write, avoid allocation if input is already owned-shape
use std::borrow::Cow;
fn normalize(s: &str) -> Cow<'_, str> {
    if s.chars().all(|c| c.is_ascii_lowercase()) { Cow::Borrowed(s) }
    else { Cow::Owned(s.to_lowercase()) }
}
 
// Interior mutability — shared aliasing + mutation through Cell / RefCell / Mutex
use std::cell::RefCell;
let v = RefCell::new(vec![1, 2]);
v.borrow_mut().push(3);

9. Gotchas

  • Borrow checker frustration: “cannot borrow as mutable because it is also borrowed as immutable” — the compiler is right; restructure (split borrows, scope shorter, intermediate let).
  • Strings: String vs &str vs &String vs Box<str>; APIs accept &str, return String; index by byte (UTF-8 boundary panic if mid-char) — use .chars() or .char_indices().
  • Integer overflow: panics in debug, wraps in release. Use checked_add/wrapping_add/saturating_add explicitly.
  • Rc<RefCell<T>> is a smell: indicates fighting the borrow checker — usually restructure ownership instead.
  • Pinning self-referential structs in async: can’t move once polled. Box::pin to heap-pin.
  • Trait object limitations: dyn Trait requires object safety (no generic methods, no Self returns).
  • Lifetime variance bugs: invariant types unexpectedly reject lifetime shortening (e.g., &mut T is invariant in T).
  • async fn in traits historically required workarounds (async-trait crate); 1.75+ supports static dispatch natively.
  • Send/Sync propagation: holding a Rc<T> makes a future !Send, breaking Tokio multi-threaded executor.
  • Cargo features are additive across the workspace: enabling a feature in one crate enables it everywhere — leads to surprise bloat.
  • unwrap() in production hides errors at runtime.
  • Macros’ error messages can be opaque; cargo expand (cargo-expand) reveals what they emit.
  • Slow compile times are real — Bevy / Tokio / serde-heavy projects easily hit 10+ minute fresh builds. Mitigations: sccache, cargo-chef (Docker), mold linker (-C link-arg=-fuse-ld=mold — 5-10x faster link), cranelift backend (debug only), workspace splitting, fewer generics.
  • impl Trait in different positions has different semantics — argument position is generic, return position is opaque type, type alias is for impl blocks. Easy to confuse.
  • Borrow-check vs RefCell runtime borrow panicRefCell::borrow_mut() while a borrow is live panics; one of the few Rust panics that’s hard to debug.
  • drop order is LIFO within a scope but reversed across struct fields (declaration order, then top-down on enclosing). Matters when types implement Drop interactively (locks).
  • Cargo’s default-features = true can pull surprises when used in workspaces; disable with default-features = false then opt in explicitly.
  • 'static doesn’t mean “lives forever” — it means “no borrowed references inside.” String is 'static, &'static str is a string literal, distinguish carefully.

2024 Edition (Feb 2025 stable)

Rust 1.85 enabled Edition 2024 by default for new projects. Headline changes:

  • if let temporary scope shrinks — fewer surprising borrow-extensions.
  • Migrating to let chains (stable 1.83): if let Some(x) = opt && x > 5 { ... }.
  • unsafe extern { fn ... } — explicit unsafe on extern blocks.
  • unsafe attributes for #[no_mangle], #[link_section], #[export_name] — they’re now #[unsafe(no_mangle)].
  • gen keyword reserved for generator blocks (gen { yield x; }) — generators in nightly.
  • Tail expressions in blocks dropped temporaries at end-of-block instead of end-of-scope — eliminates many spurious borrow-check errors.
  • macro_rules! fragment specifiers tightened (e.g., expr_2021).

Cargo.toml deep dive

[package]
name = "myapp"
version = "0.1.0"
edition = "2024"
rust-version = "1.85"   # MSRV
description = "..."
license = "MIT OR Apache-2.0"
repository = "https://github.com/me/myapp"
keywords = ["cli", "demo"]
categories = ["command-line-utilities"]
 
[dependencies]
tokio = { version = "1.40", features = ["full"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
clap = { version = "4", features = ["derive"] }
reqwest = { version = "0.12", default-features = false, features = ["rustls-tls", "json"] }
anyhow = "1"
thiserror = "2"
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
 
[dev-dependencies]
criterion = { version = "0.5", features = ["html_reports"] }
proptest = "1"
insta = "1"
 
[build-dependencies]
cc = "1"
 
[features]
default = ["json"]
json = ["dep:serde_json"]
postgres = ["dep:tokio-postgres"]
 
[[bench]]
name = "core_bench"
harness = false  # use Criterion's main, not stdlib's
 
[profile.release]
opt-level = 3
lto = "fat"          # full link-time optimization
codegen-units = 1    # slower compile, better code
panic = "abort"      # smaller binary, no unwinding
strip = true
 
[profile.release-debug]
inherits = "release"
debug = true         # keep symbols for profiling
 
[workspace]
members = ["crates/*"]
resolver = "3"       # 2024 edition default
 
[workspace.dependencies]
tokio = { version = "1.40", features = ["full"] }
 
[workspace.lints.rust]
unsafe_code = "forbid"
 
[workspace.lints.clippy]
all = "warn"
pedantic = "warn"

Compile-time + runtime characteristics (real-world 2026 numbers)

  • Release-build binary size: hello-world ~300 KB stripped; cargo new --bin with serde + tokio + reqwest typical 5-15 MB stripped. panic = "abort" + strip = true + lto = "fat" + opt-level = "z" shrinks 40-60%.
  • Compile time (Bevy game, ~300k LOC, cold): ~3 min clean release; ~10 s incremental. Cranelift backend: ~2 min cold debug, half the linker time.
  • Throughput: Axum + Tokio serves ~1M req/s on a 32-core box for “hello world” — within 5% of fasthttp (Go), 2x net/http (Go), 3-5x Express (Node), 10x Flask (Python).
  • Memory: 8 KB initial stack per task (vs Tokio’s 16 KB-ish per task incl. waker), no GC pauses. Idiomatic services run at fraction of equivalent JVM memory.

Rust version timeline (1.0 → 1.95)

Rust ships every 6 weeks. Notable releases:

VersionDateHeadline
1.0May 2015First stable
1.31Dec 2018Edition 2018 — NLL, async/await preview
1.39Nov 2019Stable async/await
1.51Mar 2021Const generics MVP
1.56Oct 2021Edition 2021 — disjoint closure captures, panic in const fn
1.65Nov 2022GATs, let-else
1.70Jun 2023OnceLock/OnceCell
1.74Nov 2023Lint config in Cargo.toml
1.75Dec 2023async fn in traits (static dispatch), RPITIT
1.78May 2024Lock APIs in std::io, diagnostic_namespace
1.80Jul 2024LazyLock/LazyCell, exclusive ranges in patterns
1.83Nov 2024const traits + let chains
1.85Feb 2025Edition 2024 default, async closures
1.88Aug 2025let chains in if/while everywhere
1.90Oct 2025More const-evaluation features
1.95Apr 2026(latest as of writing)

Roadmap focus areas through 2026-27: full async traits with dyn, Polonius borrow checker, more const-generics expressions, gradual #![forbid(unsafe_op_in_unsafe_fn)] migration, formal language spec.

Real code patterns

Axum REST API with sqlx + Postgres

use axum::{routing::{get, post}, Router, extract::{State, Path, Json}, http::StatusCode};
use sqlx::PgPool;
use serde::{Serialize, Deserialize};
use std::sync::Arc;
 
#[derive(Clone)]
struct AppState { db: PgPool }
 
#[derive(Serialize, sqlx::FromRow)]
struct User { id: i64, email: String, name: String }
 
#[derive(Deserialize)]
struct CreateUser { email: String, name: String }
 
async fn get_user(State(s): State<Arc<AppState>>, Path(id): Path<i64>)
    -> Result<Json<User>, StatusCode>
{
    let user = sqlx::query_as!(User, "SELECT id, email, name FROM users WHERE id = $1", id)
        .fetch_optional(&s.db).await
        .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?
        .ok_or(StatusCode::NOT_FOUND)?;
    Ok(Json(user))
}
 
async fn create_user(State(s): State<Arc<AppState>>, Json(input): Json<CreateUser>)
    -> Result<Json<User>, StatusCode>
{
    let user = sqlx::query_as!(User,
        "INSERT INTO users (email, name) VALUES ($1, $2) RETURNING id, email, name",
        input.email, input.name)
        .fetch_one(&s.db).await
        .map_err(|_| StatusCode::CONFLICT)?;
    Ok(Json(user))
}
 
#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let db = PgPool::connect(&std::env::var("DATABASE_URL")?).await?;
    let state = Arc::new(AppState { db });
 
    let app = Router::new()
        .route("/users/:id", get(get_user))
        .route("/users", post(create_user))
        .with_state(state);
 
    let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await?;
    axum::serve(listener, app).await?;
    Ok(())
}

Tokio + reqwest concurrent fetch with structured cancellation

use futures::future::join_all;
use std::time::Duration;
 
async fn fetch_with_timeout(client: &reqwest::Client, url: &str) -> anyhow::Result<String> {
    let resp = tokio::time::timeout(Duration::from_secs(5), client.get(url).send()).await??;
    Ok(resp.text().await?)
}
 
#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let client = reqwest::Client::new();
    let urls = vec!["https://example.com", "https://rust-lang.org"];
    let results = join_all(urls.iter().map(|u| fetch_with_timeout(&client, u))).await;
    for r in results {
        match r {
            Ok(body) => println!("got {} bytes", body.len()),
            Err(e) => eprintln!("error: {e:#}"),
        }
    }
    Ok(())
}

WASM + Component Model (2026)

Rust is the lingua franca of WebAssembly because of its no-GC, small binary, and no_std story.

  • wasm-bindgen + wasm-pack for browser JS interop.
  • cargo-component for WASI 0.2 / Component Model (WIT-based interface definitions).
  • wit-bindgen generates Rust bindings from WIT (WebAssembly Interface Types).
  • WASI Preview 2: stable as of late 2024; wasm32-wasip2 target.
  • Runtimes: Wasmtime (Bytecode Alliance), WasmEdge (CNCF), Wasmer, Spin (Fermyon, serverless), Fastly Compute@Edge, Cloudflare workerd.
  • Use cases: Cloudflare Workers, Vercel Edge, Shopify Functions, Suborbital, Microsoft AKS WASM nodes, Adobe Photoshop Web, Figma plugins.

Embedded + bare-metal Rust

Rust’s no_std + alloc + cargo + embedded-hal 1.0 (stable Jan 2024) make it the most ergonomic systems language for microcontrollers in 2026 — and the only modern alternative to C/C++ for hard real-time.

The hardware targets that ship Rust today:

FamilyTargetsNotable boards
RP2040 / RP2350thumbv6m-none-eabi, thumbv8m.main-none-eabihfRaspberry Pi Pico, Pico 2, Pimoroni Tiny 2040
ESP32 (Xtensa)xtensa-esp32-none-elf (+esp channel)Espressif dev kits, M5Stack, Adafruit
ESP32-C3 / C6 / S3 (RISC-V + Xtensa)riscv32imc-unknown-none-elf, riscv32imac-unknown-none-elfC3 supermini, C6 wifi6/zigbee, S3 + AI
STM32 F4/F7/H7thumbv7em-none-eabihfSTM32F411 BlackPill, F4 Discovery, H743 Nucleo
nRF52840 (Nordic)thumbv7em-none-eabihfnRF52840 DK, Adafruit Feather Bluefruit
Microchip SAMD51thumbv7em-none-eabihfAdafruit Feather M4, ItsyBitsy M4, PyGamer

Dev workflow:

# Install target + tools
rustup target add thumbv7em-none-eabihf
cargo install probe-rs --features cli
cargo install cargo-embed cargo-flash cargo-binutils
 
# Scaffold from a template
cargo generate --git https://github.com/rust-embedded/cortex-m-quickstart
 
# Flash + run via probe-rs (USB SWD/JTAG probe)
cargo embed --release            # flash + open RTT (real-time transfer) console
cargo flash --chip STM32F411CEUx # flash only
DEFMT_LOG=info cargo embed       # filter defmt logs

Embassy vs RTIC:

  • Embassyasync/await on bare metal. The embassy-executor is a no-alloc executor designed to live in a single static. Async HALs (embassy-stm32, embassy-nrf, embassy-rp, embassy-esp) for SPI, I2C, UART, USB, net, timers. Dominant for new projects 2025-26.
#![no_std]
#![no_main]
use embassy_executor::Spawner;
use embassy_stm32::gpio::{Level, Output, Speed};
use embassy_time::{Duration, Timer};
 
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
    let p = embassy_stm32::init(Default::default());
    let mut led = Output::new(p.PC13, Level::High, Speed::Low);
    loop {
        led.toggle();
        Timer::after(Duration::from_millis(500)).await;
    }
}
  • RTIC 2 — message-passing + priority-based preemption via interrupt vectors. Hard real-time with deterministic latency. v2 (2024) added async tasks alongside hardware-priority tasks.
  • defmt — deferred formatting; ~10 bytes/log on the wire, host PC reformats. 100x faster than uart_writeln!. Pair with probe-rs run for live RTT streaming.

no_std + alloc opt-in gives you Box / Vec / String against a global allocator (e.g. embedded-alloc bump-pointer). For zero-alloc code, heapless has stack-only Vec<T, N>, String<N>, FnvIndexMap<K, V, N> with capacity in the type.

Rust web ecosystem 2026 (real-world stacks)

Reference 2026 web service stack: Axum + Tower + Tracing + sqlx + Postgres + Redis — used at Discord, parts of Cloudflare, Shopify, AWS internal services.

use axum::{Router, routing::get};
use sqlx::PgPool;
use tower_http::{trace::TraceLayer, compression::CompressionLayer};
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
 
#[derive(Clone)]
struct AppState { db: PgPool }
 
#[tokio::main]
async fn main() -> anyhow::Result<()> {
    tracing_subscriber::registry()
        .with(tracing_subscriber::EnvFilter::new("info"))
        .with(tracing_subscriber::fmt::layer().json())
        .init();
 
    let db = PgPool::connect(&std::env::var("DATABASE_URL")?).await?;
    sqlx::migrate!("./migrations").run(&db).await?;
 
    let app = Router::new()
        .route("/health", get(|| async { "ok" }))
        .layer(TraceLayer::new_for_http())
        .layer(CompressionLayer::new())
        .with_state(AppState { db });
 
    let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await?;
    axum::serve(listener, app).await?;
    Ok(())
}

ORM landscape:

  • sqlx — compile-time SQL checking against a live dev DB; dominant for greenfield.
  • Diesel 2.x — synchronous, fastest ORM, DSL-based; diesel-async for async.
  • sea-orm — async, ActiveRecord-style, codegen from DB schema.

Pooling: deadpool-postgres if you skip the ORM; redis-rs + fred for Redis; mongodb crate is official.

Edge / serverless platforms with native Rust support:

PlatformBuild/devCold startRuntime
Cloudflare Workerswrangler dev + worker-rs → wasm32-unknown-unknown<1msV8 isolate + wasm
Fermyon Spinspin watch + spin-sdk → wasm32-wasip2~5msWasmtime
Fastly Compute@Edgeviceroy local + fastly crate → wasm32-wasip1~10msLucet/Wasmtime
AWS Lambdacargo lambda build --release --arm64~80msFirecracker μVM

Cloudflare Workers Rust example:

use worker::*;
 
#[event(fetch)]
async fn main(req: Request, env: Env, _ctx: Context) -> Result<Response> {
    Router::new()
        .get_async("/users/:id", |_req, ctx| async move {
            let id = ctx.param("id").unwrap();
            let kv = ctx.kv("USERS")?;
            match kv.get(id).text().await? {
                Some(v) => Response::ok(v),
                None => Response::error("not found", 404),
            }
        })
        .run(req, env).await
}

Build: wrangler deploy --compatibility-date=2026-01-01. Pair with Durable Objects + R2 + D1 for stateful edge.

10. Citations