--- name: rust-best-practices description: > Idiomatic Rust guide based on Apollo GraphQL's best practices handbook. Use when writing, reviewing, or refactoring Rust - ownership and borrowing decisions, Result error handling, performance, clippy, and tests. license: MIT compatibility: Rust 1.70+, Cargo metadata: author: apollographql version: "1.1.0" allowed-tools: Bash(cargo:*) Bash(rustc:*) Bash(rustfmt:*) Bash(clippy:*) Read Write Edit Glob Grep --- # Rust Best Practices Apply these guidelines when writing or reviewing Rust code. Based on Apollo GraphQL's [Rust Best Practices Handbook](https://github.com/apollographql/rust-best-practices). ## Best Practices Reference Before reviewing, familiarize yourself with Apollo's Rust best practices. Read ALL relevant chapters in the same turn in parallel. Reference these files when providing feedback: - [Chapter 1 - Coding Styles and Idioms](references/chapter_01.md): Borrowing vs cloning, Copy trait, Option/Result handling, iterators, comments - [Chapter 2 - Clippy and Linting](references/chapter_02.md): Clippy configuration, important lints, workspace lint setup - [Chapter 3 - Performance Mindset](references/chapter_03.md): Profiling, avoiding redundant clones, stack vs heap, zero-cost abstractions - [Chapter 4 - Error Handling](references/chapter_04.md): Result vs panic, thiserror vs anyhow, error hierarchies - [Chapter 5 - Automated Testing](references/chapter_05.md): Test naming, one assertion per test, snapshot testing Trimmed to the chapters that apply here. The only Rust in this workspace is `work/realness/tracer`, a ~300-line WASM `cdylib` with no threads, no `unsafe`, no trait objects, and no published rustdoc API. Apollo's chapters 6-9 (generics and dispatch, type state, comments vs documentation, pointers and `Send`/`Sync`) were dropped as inapplicable. Pull them from the [upstream handbook](https://github.com/apollographql/rust-best-practices) if a future crate needs them. ## Quick Reference ### Borrowing & Ownership - Prefer `&T` over `.clone()` unless ownership transfer is required - Use `&str` over `String`, `&[T]` over `Vec` in function parameters - Small `Copy` types (24 bytes or less) can be passed by value - Use `Cow<'_, T>` when ownership is ambiguous ### Error Handling - Return `Result` for fallible operations; avoid `panic!` in production - Never use `unwrap()`/`expect()` outside tests - Use `thiserror` for library errors, `anyhow` for binaries only - Prefer `?` operator over match chains for error propagation ### Performance - Always benchmark with `--release` flag - Run `cargo clippy -- -D clippy::perf` for performance hints - Avoid cloning in loops; use `.iter()` instead of `.into_iter()` for Copy types - Prefer iterators over manual loops; avoid intermediate `.collect()` calls ### Linting Run regularly: `cargo clippy --all-targets --all-features --locked -- -D warnings` Key lints to watch: - `redundant_clone` - unnecessary cloning - `large_enum_variant` - oversized variants (consider boxing) - `needless_collect` - premature collection Use `#[expect(clippy::lint)]` over `#[allow(...)]` with justification comment. ### Testing - Name tests descriptively: `process_should_return_error_when_input_empty()` - One assertion per test when possible - Use doc tests (`///`) for public API examples - Consider `cargo insta` for snapshot testing generated output ### Comments - `//` comments explain *why* (safety, workarounds, design rationale) - Every `TODO` needs a linked issue: `// TODO(#42): ...`