Rust Idioms and Patterns
Rust type system + ownership model = primary correctness tools. Lean into compiler — strongest ally. Idiomatic, safe, expressive.
Scope: Rust coding idioms. Layout: @.gemini/skills/project-structure-rust/SKILL.md. Test naming: GEMINI.md § Testing Strategy. Logging: @.gemini/skills/logging-and-observability-principles/SKILL.md.
Ownership and Borrowing
Prefer borrowing (&T, &mut T) over cloning. Never .clone() to silence borrow checker without // CLONE: comment. Use Cow<'_, T> when may/may not need ownership. Prefer &str over String, &[T] over Vec<T> in params.
Minimize owned data in structs. References + lifetimes for short-lived. Owned types when struct outlives inputs.
Avoid unnecessary Arc<Mutex<T>>: channels for one-directional, RwLock for read-heavy, Arc<T> (no lock) for immutable-after-init.
Error Handling
? for propagation — never unwrap() in production. Acceptable only in tests, infallible ops with // SAFETY: comment, CLI main() with expect("reason").
Error crates by context: library = thiserror (typed enums), application = anyhow (ergonomic chaining). Never mix: libs must not depend on anyhow.
Error type design:
// ✅ Typed, matchable
#[derive(Debug, thiserror::Error)]
pub enum PathfinderError {
#[error("file not found: {path}")]
FileNotFound { path: PathBuf },
#[error("AST parse failed: {0}")]
ParseError(String),
#[error(transparent)]
Io(#[from] std::io::Error),
}
// ❌ Stringly-typed, unmatchable
fn do_thing() -> Result<(), String> { ... }
// ✅ Force callers to handle
#[must_use]
pub fn create_task(req: CreateTaskRequest) -> Result<Task, TaskError> { ... }
Async and Concurrency
tokio runtime. #[tokio::main]/#[tokio::test]. tokio::spawn over std::thread::spawn. tokio::select! for racing futures.
Cancellation safety: prefer tokio::sync::mpsc over broadcast. Document cancellation on async fns holding resources across .await. Use CancellationToken for shutdown.
Blocking ops: never blocking I/O in async. Use tokio::task::spawn_blocking. Use tokio::fs not std::fs in async.
Unsafe Code
Zero unsafe except FFI boundaries (tree-sitter C bindings etc). Every unsafe needs // SAFETY: comment.
Minimize surface: encapsulate in safe wrapper. Public API safe from any context. Test boundary conditions.
Never unsafe to bypass borrow checker — restructure instead.
Lifetimes and Generics
Prefer '_ elision. Named lifetimes only when required/clarifying. 'a for single, descriptive ('input, 'query) for multiple.
Simple generic bounds. Concrete for prototyping, generics when pattern stabilizes. impl Trait for simple, where clauses for complex.
Avoid lifetime gymnastics. Complex annotations -> restructure to owned data or Arc. Consider "split borrow" pattern.
Idiomatic Patterns
- Builder pattern —
Self return for chaining, build() returns Result<T, BuildError>.
- Newtype — wrap primitives:
struct UserId(u64). Deref only for true "is-a".
- Typestate — different states = different types. Invalid transitions = compile errors.
From/Into — implement From<A> for B (never Into directly). Use thiserror's #[from].
Testing
Organization (Rust-specific):
- Unit:
#[cfg(test)] mod tests at bottom of each .rs file. Access private fns via use super::*. Stripped from production. Never create *_test.rs files.
- Integration:
tests/ at crate root (separate crates). Public API only. Shared helpers: tests/common/mod.rs (NOT tests/common.rs).
#[tokio::test] for async.
Naming: fn test_<function>_<scenario>_<expected>() (snake_case).
Assertions: assert_eq!/assert_ne! over assert!(a == b). assert!(matches!(result, Ok(_))) for variants.
Property testing: proptest or quickcheck for wide input spaces.
Clippy and Formatting
cargo check for fast iteration. cargo clippy before commit. cargo build only for artifacts. Never cargo build during TDD.
cargo clippy zero warnings. #[allow(clippy::...)] only with // ALLOW: comment.
cargo fmt non-negotiable.
Recommended config:
[lints.clippy]
pedantic = "warn"
unwrap_used = "deny"
expect_used = "warn"
Dependency Management
- Minimize count — each dep = attack surface + compile cost.
- Pin major versions:
dep = "1" not dep = "*".
cargo audit regularly.
- Prefer well-maintained crates (downloads, last commit, issue tracker).
Related
- Error Handling Principles GEMINI.md § Error Handling Principles
- Concurrency and Threading Principles @.gemini/skills/concurrency-and-threading-principles/SKILL.md
- Concurrency and Threading Mandate GEMINI.md § Concurrency and Threading Mandate
- Performance Optimization Principles @.gemini/skills/performance-optimization-principles/SKILL.md
- Resource and Memory Management Principles @.gemini/skills/resources-and-memory-management/SKILL.md
- Security Mandate GEMINI.md § Security Mandate
- Code Idioms and Conventions GEMINI.md § Code Idioms and Conventions
- Testing Strategy GEMINI.md § Testing Strategy
- Dependency Management Principles @.gemini/skills/dependency-management-principles/SKILL.md
1---2name: rust-idioms3description: Rust Idioms and Patterns4---56## Rust Idioms and Patterns78Rust type system + ownership model = primary correctness tools. Lean into compiler — strongest ally. Idiomatic, safe, expressive.910> Scope: Rust coding idioms. Layout: `@.gemini/skills/project-structure-rust/SKILL.md`. Test naming: GEMINI.md § Testing Strategy. Logging: `@.gemini/skills/logging-and-observability-principles/SKILL.md`.1112### Ownership and Borrowing13141. **Prefer borrowing (`&T`, `&mut T`) over cloning.** Never `.clone()` to silence borrow checker without `// CLONE:` comment. Use `Cow<'_, T>` when may/may not need ownership. Prefer `&str` over `String`, `&[T]` over `Vec<T>` in params.15162. **Minimize owned data in structs.** References + lifetimes for short-lived. Owned types when struct outlives inputs.17183. **Avoid unnecessary `Arc<Mutex<T>>`:** channels for one-directional, `RwLock` for read-heavy, `Arc<T>` (no lock) for immutable-after-init.1920### Error Handling21221. **`?` for propagation — never `unwrap()` in production.** Acceptable only in tests, infallible ops with `// SAFETY:` comment, CLI `main()` with `expect("reason")`.23242. **Error crates by context:** library = `thiserror` (typed enums), application = `anyhow` (ergonomic chaining). Never mix: libs must not depend on `anyhow`.25263. **Error type design:**2728```rust29// ✅ Typed, matchable30#[derive(Debug, thiserror::Error)]31pub enum PathfinderError {32 #[error("file not found: {path}")]33 FileNotFound { path: PathBuf },34 #[error("AST parse failed: {0}")]35 ParseError(String),36 #[error(transparent)]37 Io(#[from] std::io::Error),38}3940// ❌ Stringly-typed, unmatchable41fn do_thing() -> Result<(), String> { ... }4243// ✅ Force callers to handle44#[must_use]45pub fn create_task(req: CreateTaskRequest) -> Result<Task, TaskError> { ... }46```4748### Async and Concurrency49501. **`tokio` runtime.** `#[tokio::main]`/`#[tokio::test]`. `tokio::spawn` over `std::thread::spawn`. `tokio::select!` for racing futures.51522. **Cancellation safety:** prefer `tokio::sync::mpsc` over broadcast. Document cancellation on async fns holding resources across `.await`. Use `CancellationToken` for shutdown.53543. **Blocking ops:** never blocking I/O in async. Use `tokio::task::spawn_blocking`. Use `tokio::fs` not `std::fs` in async.5556### Unsafe Code57581. **Zero `unsafe` except FFI boundaries** (tree-sitter C bindings etc). Every `unsafe` needs `// SAFETY:` comment.59602. **Minimize surface:** encapsulate in safe wrapper. Public API safe from any context. Test boundary conditions.61623. **Never `unsafe` to bypass borrow checker** — restructure instead.6364### Lifetimes and Generics65661. **Prefer `'_` elision.** Named lifetimes only when required/clarifying. `'a` for single, descriptive (`'input`, `'query`) for multiple.67682. **Simple generic bounds.** Concrete for prototyping, generics when pattern stabilizes. `impl Trait` for simple, `where` clauses for complex.69703. **Avoid lifetime gymnastics.** Complex annotations -> restructure to owned data or `Arc`. Consider "split borrow" pattern.7172### Idiomatic Patterns73741. **Builder pattern** — `Self` return for chaining, `build()` returns `Result<T, BuildError>`.752. **Newtype** — wrap primitives: `struct UserId(u64)`. `Deref` only for true "is-a".763. **Typestate** — different states = different types. Invalid transitions = compile errors.774. **`From`/`Into`** — implement `From<A> for B` (never `Into` directly). Use `thiserror`'s `#[from]`.7879### Testing80811. **Organization (Rust-specific):**82 - **Unit:** `#[cfg(test)] mod tests` at bottom of each `.rs` file. Access private fns via `use super::*`. Stripped from production. Never create `*_test.rs` files.83 - **Integration:** `tests/` at crate root (separate crates). Public API only. Shared helpers: `tests/common/mod.rs` (NOT `tests/common.rs`).84 - `#[tokio::test]` for async.85862. **Naming:** `fn test_<function>_<scenario>_<expected>()` (snake_case).873. **Assertions:** `assert_eq!`/`assert_ne!` over `assert!(a == b)`. `assert!(matches!(result, Ok(_)))` for variants.884. **Property testing:** `proptest` or `quickcheck` for wide input spaces.8990### Clippy and Formatting91921. **`cargo check`** for fast iteration. `cargo clippy` before commit. `cargo build` only for artifacts. Never `cargo build` during TDD.93942. **`cargo clippy` zero warnings.** `#[allow(clippy::...)]` only with `// ALLOW:` comment.95963. **`cargo fmt` non-negotiable.**97984. **Recommended config:**99```toml100[lints.clippy]101pedantic = "warn"102unwrap_used = "deny"103expect_used = "warn"104```105106### Dependency Management107- Minimize count — each dep = attack surface + compile cost.108- Pin major versions: `dep = "1"` not `dep = "*"`.109- `cargo audit` regularly.110- Prefer well-maintained crates (downloads, last commit, issue tracker).111112### Related113- Error Handling Principles GEMINI.md § Error Handling Principles114- Concurrency and Threading Principles @.gemini/skills/concurrency-and-threading-principles/SKILL.md115- Concurrency and Threading Mandate GEMINI.md § Concurrency and Threading Mandate116- Performance Optimization Principles @.gemini/skills/performance-optimization-principles/SKILL.md117- Resource and Memory Management Principles @.gemini/skills/resources-and-memory-management/SKILL.md118- Security Mandate GEMINI.md § Security Mandate119- Code Idioms and Conventions GEMINI.md § Code Idioms and Conventions120- Testing Strategy GEMINI.md § Testing Strategy121- Dependency Management Principles @.gemini/skills/dependency-management-principles/SKILL.md