Skip to content

@tank/rust-patterns

1.0.0

Description

Idiomatic Rust patterns for production apps. Ownership, borrowing, lifetimes, error handling (thiserror, anyhow), traits, generics, async/Tokio, design patterns (newtype, typestate, builder), serde, testing, CLI (clap, tracing), web (axum, sqlx), performance, and crate recommendations.

Triggered by

rustownershipborrowinglifetimesborrow checkererror handling
Download
Verified
tank install @tank/rust-patterns

Rust Patterns

Core Philosophy

  1. Ownership is the architecture -- Every design decision flows from ownership. Decide who owns data first, then choose the borrowing strategy. Fighting the borrow checker means the ownership model is wrong.
  2. Make illegal states unrepresentable -- Use enums, newtypes, and typestate patterns so invalid program states cannot compile. Move runtime checks to compile-time guarantees wherever possible.
  3. Errors are values, not exceptions -- Return Result<T, E> for recoverable errors. Reserve panic! for programming bugs only. Libraries expose typed errors; applications use anyhow for ergonomic propagation.
  4. Zero-cost abstractions pay off -- Prefer iterators over manual loops, generics over trait objects, stack allocation over heap. The compiler optimizes aggressively when given type information.
  5. Explicit over implicit -- Rust rewards explicitness. Derive only what you need, annotate lifetimes when the compiler asks, prefer concrete types over dynamic dispatch unless polymorphism is required.

Quick-Start: Common Problems

"The borrow checker rejects my code"

Error PatternLikely Fix
Cannot borrow as mutable, already borrowedSplit borrows into non-overlapping scopes or use .clone()
Does not live long enoughMove owned data instead of borrowing, or restructure ownership
Cannot move out of borrowed contentUse .clone(), mem::take, or redesign to avoid the move
Multiple mutable borrowsUse RefCell (single-thread) or Mutex (multi-thread) for interior mutability
-> See references/ownership-borrowing-lifetimes.md

"Which error handling approach?"

ContextUse
Library cratethiserror -- define typed error enum with #[error] and #[from]
Application binaryanyhow::Result -- ergonomic ? propagation with context
Converting between error typesimpl From<SourceError> for MyError or #[from] in thiserror
Adding context to errorsanyhow::Context trait -- .context("failed to open config")
-> See references/error-handling.md

"How do I structure async code?"

  1. Use #[tokio::main] for the entry point with the multi-thread runtime
  2. Spawn CPU-bound work with spawn_blocking, not spawn
  3. Communicate between tasks via channels (mpsc, oneshot, watch)
  4. Use tokio::select! for racing concurrent futures -> See references/async-tokio.md

"How do I serialize complex types?"

  1. Derive Serialize / Deserialize for simple structs
  2. Use #[serde(rename_all = "camelCase")] for API compatibility
  3. Use #[serde(tag = "type")] for internally tagged enums
  4. Implement custom serialization only when derive attributes are insufficient -> See references/serde-patterns.md

Decision Trees

Smart Pointer Selection

NeedUse
Heap allocation, single ownerBox<T>
Shared ownership, single-threadRc<T>
Shared ownership, multi-threadArc<T>
Interior mutability, single-threadCell<T> (Copy) or RefCell<T> (non-Copy)
Interior mutability, multi-threadMutex<T> or RwLock<T>
Borrow or own conditionallyCow<'a, T>
Self-referential / async pinningPin<Box<T>>

Trait Object vs Generic

SignalUse
Known set of types at compile timeGeneric (impl Trait or <T: Trait>)
Heterogeneous collection at runtimeTrait object (Box<dyn Trait> or &dyn Trait)
Performance-critical hot pathGeneric (monomorphization, zero-cost)
Reducing compile times / binary sizeTrait object (single implementation)
Need object safetyTrait object (no Self in return position, no generics on methods)

Crate Selection

TaskRecommended Crate
Async runtimetokio
Web frameworkaxum
HTTP clientreqwest
Databasesqlx (compile-checked SQL) or diesel (query builder)
Serializationserde + serde_json / toml
CLI parsingclap (derive)
Logging / tracingtracing + tracing-subscriber
Error handling (lib)thiserror
Error handling (app)anyhow
Property testingproptest

Reference Index

FileContents
references/ownership-borrowing-lifetimes.mdOwnership rules, borrowing, lifetime annotations, elision, smart pointers, interior mutability, common borrow checker fixes
references/error-handling.mdResult/Option combinators, thiserror, anyhow, custom error types, error conversion, library vs application patterns
references/traits-generics.mdTrait definitions, default methods, associated types, trait objects, blanket impls, generics, where clauses, supertraits
references/async-tokio.mdTokio runtime, spawn, channels, select!, timeouts, cancellation, stream processing, common async pitfalls
references/design-patterns.mdNewtype, typestate, builder, From/Into conversions, enum dispatch, strategy via closures, RAII guards
references/serde-patterns.mdDerive attributes, rename, flatten, tagged enums, custom serialization, skip, default, serde_with
references/testing-patterns.mdUnit tests, integration tests, test organization, fixtures, proptest, mocking, async test patterns
references/ecosystem-crates.mdAxum, sqlx, clap, tracing, reqwest, indicatif, Cargo workspaces, module organization, feature flags
references/performance.mdIterators, zero-copy, Cow, SmallVec, allocation strategies, benchmarking, compiler hints, SIMD, unsafe guidelines

Command Palette

Search skills, docs, and navigate Tank