--- name: rust-best-practices description: > Guide for writing idiomatic Rust code based on Apollo GraphQL's best practices handbook. Use this skill when: (1) writing new Rust code or functions, (2) reviewing or refactoring existing Rust code, (3) deciding between borrowing vs cloning or ownership patterns, (4) implementing error handling with Result types, (5) optimizing Rust code for performance, (6) writing tests or documentation for Rust projects. license: MIT compatibility: Rust 1.70+, Cargo metadata: author: apollographql version: "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. ## 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) 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 ### Generics & Dispatch - Prefer generics (static dispatch) for performance-critical code - Use `dyn Trait` only when heterogeneous collections are needed - Box at API boundaries, not internally ### Type State Pattern Encode valid states in the type system to catch invalid operations at compile time: ```rust struct Connection { /* ... */ _state: PhantomData } struct Disconnected; struct Connected; impl Connection { fn send(&self, data: &[u8]) { /* only connected can send */ } } ``` ### Documentation - `//` comments explain *why* (safety, workarounds, design rationale) - `///` doc comments explain *what* and *how* for public APIs - Every `TODO` needs a linked issue: `// TODO(#42): ...` - Enable `#![deny(missing_docs)]` for libraries ## Detailed References For in-depth guidance on specific topics: - **Coding style & idioms**: See [references/style.md](references/style.md) for borrowing patterns, Option/Result handling, iterator usage, and import organization - **Error handling**: See [references/errors.md](references/errors.md) for thiserror patterns, error hierarchies, and testing errors - **Performance**: See [references/performance.md](references/performance.md) for profiling, memory layout, and iterator optimization - **Testing**: See [references/testing.md](references/testing.md) for test organization, snapshot testing, and assertion strategies - **Advanced patterns**: See [references/advanced.md](references/advanced.md) for generics, dispatch, type state, and pointer types