Modern Rust Rules
Idiomatic Rust: ownership, error handling with ?, traits, modules, cargo.
# CLAUDE.md — Modern Rust
## Edition & toolchain
- Use the latest stable Rust edition. Set `edition = "2024"` (or current) in `Cargo.toml`.
- Pin the toolchain in `rust-toolchain.toml` for reproducibility.
- `cargo fmt`, `cargo clippy --all-targets --all-features -- -D warnings` in CI. No exceptions.
## Project layout
```
Cargo.toml
src/
lib.rs # public API
main.rs # binary, if any
error.rs # crate-level errors
domain/
infra/
tests/ # integration tests
benches/
```
- For multi-crate projects, use a workspace with members. Keep crates focused — one responsibility each.
## Ownership & borrowing
- Default to **owned** types in function signatures (`String`, `Vec<T>`) when the function takes ownership; **slices** (`&str`, `&[T]`) when it borrows. Don't take `&String` or `&Vec<T>`.
- Prefer iterators over indexed loops. They're easier for the borrow checker and the compiler.
- Lifetimes: elide when possible. Name them only when the compiler asks for it.
## Errors
- Two error styles for two contexts:
- **Library**: a typed error enum with `thiserror`. Each variant tells the caller exactly what went wrong.
- **Application**: `anyhow::Result<T>` for "I just want to bubble errors up with context".
- Add context with `.context(...)` (anyhow) or `.map_err(|e| MyError::Foo { source: e })` (thiserror).
- Use `?` for propagation. Don't `unwrap` or `expect` outside tests and `main` — even `main` should bubble errors with `Result`.
## Structs & traits
- Derive aggressively when it makes sense: `Debug`, `Clone`, `PartialEq`, `Eq`, `Hash`. Don't derive `Default` blindly — it constructs an "empty" value that may not be valid.
- Builder pattern for structs with many optional fields. Use `bon` or `derive_builder` to avoid boilerplate.
- Don't write trait objects (`Box<dyn Trait>`) when generics work. Reach for `dyn` only when you genuinely need heterogeneous types.
## Modules
- One module per file. The directory pattern (`mod.rs` → `module.rs` + folder) is preferred over the older single-file form for anything beyond trivial.
- `pub` is opt-in. Most items stay private.
- Re-export via `pub use` to flatten the public API. Consumers shouldn't have to know your internal layout.
## Cargo features
- Use features for optional functionality, not for two ways of doing the same thing.
- Document features in `Cargo.toml` and `README`.
- `default-features = false` when consuming a dep — explicit > implicit.
## Performance
- Profile with `cargo flamegraph` or `samply` before optimizing.
- Avoid unnecessary allocations in hot loops. Reach for `&str` over `String` when you can.
- `cargo bench` with **criterion** for serious benchmarks.
## Don't
- Don't use `unwrap()` outside tests, examples, and prototypes. Even there, prefer `expect("explanation")`.
- Don't use `Rc<RefCell<T>>` to "fix" a borrow-checker problem. Redesign the ownership.
- Don't add `unsafe` without a comment explaining the safety invariant.
- Don't write `.clone()` to silence a borrow error. Understand what's actually moving.
Other Rust templates
Rust + Axum Web Server
Axum routers, extractors, middleware, and structured error responses.
Rust + Tokio Async Patterns
Tokio fundamentals: tasks, select!, channels, cancellation, join!.
Rust CLI Tools (clap)
Build polished CLIs with clap derive, anyhow, and structured logging.
Rust Testing Patterns
Unit tests, integration tests, doctests, proptest, and CI patterns.