From rust-1337
Rust production patterns. Use when: building Rust CLI, backend, frontend, or native apps. Covers axum, tonic, sqlx, Leptos, Dioxus, Tauri, clap, tokio. Production gotchas (blocking, cancellation, mutex), ownership decisions, crate selection. Routes to specialized domains: embedded, FFI, proc-macros, proxies/data-plane.
npx claudepluginhub yzavyas/claude-1337 --plugin rust-1337This skill uses the workspace's default tool permissions.
Production-grade patterns that separate competent from exceptional Rust developers.
Generates design tokens/docs from CSS/Tailwind/styled-components codebases, audits visual consistency across 10 dimensions, detects AI slop in UI.
Records polished WebM UI demo videos of web apps using Playwright with cursor overlay, natural pacing, and three-phase scripting. Activates for demo, walkthrough, screen recording, or tutorial requests.
Delivers idiomatic Kotlin patterns for null safety, immutability, sealed classes, coroutines, Flows, extensions, DSL builders, and Gradle DSL. Use when writing, reviewing, refactoring, or designing Kotlin code.
Production-grade patterns that separate competent from exceptional Rust developers.
.clone() is a decision about allocation (community convention)Heuristic from Steve Klabnik (Rust core team, 12+ years experience): "Following this rule will get you through 95% of situations."
| Context | Use | Why |
|---|---|---|
| Struct fields | String | Owned data lives with struct |
| Function params | &str | Accept any string via deref |
| Return (from input) | &str | Zero-cost slice |
| Return (newly created) | String | Caller needs ownership |
| Conditional modification | Cow<'_, str> | Clone-on-write |
| Factor | Generics | dyn Trait |
|---|---|---|
| Performance | Faster (static dispatch) | Slower (vtable) |
| Binary size | Larger | Smaller |
| Heterogeneous collections | No | Yes |
Rule: Default to generics. Use dyn for heterogeneous collections or plugin systems.
Writing a library?
├── YES → thiserror (callers match on variants)
└── NO (application) → Need pretty diagnostics?
├── YES → color-eyre (CLI) or miette (source snippets)
└── NO → anyhow
| Workload | Choice | Rule |
|---|---|---|
| CPU-bound | Threads / spawn_blocking | Never block async workers |
| High-concurrency I/O | Async | Scales to millions |
| Simple concurrency | Threads | Avoid async complexity |
Guideline: Keep work between .await points brief (microseconds to tens of milliseconds). Tokio uses cooperative scheduling with budget-based yielding since v0.2.14 — tasks that exceed budget get nudged to yield, but long-running sync work still starves the runtime (tokio preemption blog).
Well-established patterns from tokio documentation and production experience.
spawn_blocking() for CPU work; async alternatives for I/O// Wrong
async fn bad() {
std::thread::sleep(Duration::from_secs(2)); // Blocks worker
}
// Correct
async fn good() {
tokio::task::spawn_blocking(|| heavy_computation()).await.unwrap();
}
std::sync::Mutex guard held across .await deadlocks (tokio shared-state tutorial)await_holding_lock catches this)tokio::sync::Mutex// Deadlock risk
async fn bad(mutex: Arc<std::sync::Mutex<i32>>) {
let guard = mutex.lock().unwrap();
some_async_op().await; // Guard held!
}
// Safe: explicit drop
async fn good(mutex: Arc<std::sync::Mutex<i32>>) {
{
let mut guard = mutex.lock().unwrap();
*guard += 1;
} // Dropped before await
some_async_op().await;
}
read is safe, read_line is NOTCancellationToken (tokio-util)select! or timeout, verify each branch's cancellation safety in docscargo tree --edges features (Cargo book)default-features = falsecargo tree -e features -i <crate> to check resolutionclone(), to_string(), format!(), Vec growth (community pattern)perf lintswith_capacity(), SmallVec, Cow, shrink_to_fit()Rc<RefCell<T>> cycles leak memory (Rust Book ch15)Weak<T> for back-edges; consider arenas| Obsolete | Replacement | Reference |
|---|---|---|
lazy_static! | std::sync::LazyLock | Rust 1.80 |
once_cell (most uses) | std::sync::OnceLock | Rust 1.70 |
async-std | smol (or tokio) | Deprecated March 2025 |
structopt | clap v4 derive | clap 3.0 release |
async-trait (some cases) | Native async fn in traits | Rust 1.75 |
| async closure workarounds | Native async || {} closures | Rust 1.85 |
ansi_term | nu-ansi-term | RUSTSEC-2021-0139 |
wee_alloc | Default allocator or Talc | RUSTSEC-2022-0054 |
Note: async-trait still needed for dyn Trait with async methods.
Compile-time type safety for IDs:
struct UserId(u64);
struct OrderId(u64);
fn process_user(id: UserId) { /* ... */ }
// process_user(OrderId(1)); // Won't compile!
struct ConfigBuilder {
required_field: Option<String>,
optional_field: Option<i32>,
}
impl ConfigBuilder {
fn required_field(mut self, val: String) -> Self {
self.required_field = Some(val);
self
}
fn build(self) -> Result<Config, BuilderError> {
Ok(Config {
required_field: self.required_field.ok_or(BuilderError::MissingField)?,
optional_field: self.optional_field.unwrap_or_default(),
})
}
}
Use typed-builder crate in production.
Compile-time state machine enforcement:
struct Connection<State> { /* ... */ _state: PhantomData<State> }
struct Disconnected;
struct Connected;
struct Authenticated;
impl Connection<Disconnected> {
fn connect(self) -> Connection<Connected> { /* ... */ }
}
impl Connection<Connected> {
fn authenticate(self, creds: &str) -> Connection<Authenticated> { /* ... */ }
}
impl Connection<Authenticated> {
fn query(&self, sql: &str) -> Result<Data, Error> { /* ... */ }
}
// Can't call query() on unauthenticated connection - won't compile
When to use: Required state transitions, protocol implementations.
// Bad
fn validate(data: &str, strict: bool) { /* ... */ }
// Good
enum Validation { Strict, Lenient }
fn validate(data: &str, mode: Validation) { /* ... */ }
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("invalid input: {0}")]
InvalidInput(String),
#[error("network error")]
Network(#[from] std::io::Error),
#[error(transparent)]
Other(#[from] anyhow::Error),
}
pub type Result<T> = std::result::Result<T, Error>;
use anyhow::{Context, Result, bail, ensure};
fn process() -> Result<()> {
let data = read_file()
.with_context(|| format!("failed to read config"))?;
ensure!(!data.is_empty(), "config file is empty");
if invalid(&data) {
bail!("invalid configuration format");
}
Ok(())
}
Rules:
.unwrap() in library code.expect() without useful message// Anti-pattern: decoupled check
if !users.is_empty() { let user = users[0]; }
// Better: coupled via match
match users.as_slice() {
[] => handle_empty(),
[single] => handle_one(single),
[first, ..] => handle_multiple(first),
}
Insight: "Data lives forever or for duration of event loop."
Copy IDs instead of referenceslet sorted = {
let mut temp = get_data();
temp.sort();
temp // Immutable from here
};
Ext (RFC 445)Load reference based on project context:
| Detected | Load |
|---|---|
clap, lexopt, CLI binary | cli.md |
axum, tonic, sqlx, API/service | backend.md |
leptos, dioxus, wasm-bindgen, browser WASM | frontend.md |
tauri, egui, desktop/mobile app | native.md |
#![no_std], cortex-m, embassy, rtic | embedded.md |
pingora, rama, proxy, xds | data-plane.md |
bindgen, cbindgen, cxx, PyO3, unsafe | ffi-unsafe.md |
proc-macro = true, syn, quote | proc-macros.md |
reqwest, HTTP client, protocols | networking.md |
| Crate selection questions | ecosystem.md |
| Project setup, CI, configs | tooling.md |
| Deep async patterns, tokio internals | async.md |
| Don't | Do | Why |
|---|---|---|
.unwrap() in libs | Return Result | Callers can't recover |
.clone() to fix borrow checker | Redesign ownership | Hidden allocation, wrong model |
Arc<Mutex<T>> everywhere | Channels, message passing | Deadlock risk, contention |
String for everything | Newtypes, enums | Type safety |
pub by default | pub(crate), minimal exposure | API surface control |
Hold mutex across .await | Drop before await | Deadlock |
lazy_static! | LazyLock | Deprecated |
| Block in async | spawn_blocking | Starves runtime |
cargo clippy -- -W clippy::pedantic # Lints
cargo nextest run # Faster tests | cargo deny check # Deps
cargo tree --edges features # Feature resolution
cargo bloat --release # Binary size
| Need | Crate |
|---|---|
| Errors (lib) | thiserror |
| Errors (app) | anyhow |
| Serialization | serde, serde_json, toml |
| CLI | clap (or lexopt for minimal) |
| Async | tokio |
| HTTP | reqwest (client), axum (server) |
| Logging | tracing |
| Testing | proptest, nextest, insta |