<< All versions
Skill v1.0.0
currentAutomated scan100/100lugassawan/swe-workbench/language-rust
──Details
PublishedSeptember 27, 2026 at 09:11 AM
Content Hashsha256:039bb0b4dba66b1a...
Git SHAe387170b21ee
──Files
Files (1 file, 4.1 KB)
SKILL.md4.1 KBactive
SKILL.md · 98 lines · 4.1 KB
version: "1.0.0" name: language-rust description: Rust idioms — ownership, lifetimes, and iterators. Auto-load when working with .rs files, Cargo.toml, or when the user mentions Rust, cargo, ownership, borrow checker, lifetime, or async Rust.
Rust
Ownership in one paragraph
Every value has one owner. Passing by value moves; borrow with & (shared, many) or &mut (exclusive, one). Shared and mutable references cannot coexist. Most "fights with the borrow checker" are a design smell — the data model mixed ownership and sharing.
Borrowing rules of thumb
&Twhen you only read.&mut Twhen you mutate in place.T(by value) when you consume — builders, transforming constructors.- Return owned types unless the caller clearly benefits from a borrow tied to a parameter's lifetime.
Lifetimes
- Start without annotations; add them when the compiler asks.
'staticdoes not mean "lives forever" — it means "no non-static references inside". Prefer owned types over'staticjuggling.- If a struct needs many lifetimes, consider owned data or
Arcinstead.
Error handling
- Return
Result<T, E>; use?to propagate. - Library code: custom enum with
thiserror. - Application code:
anyhow::Errorfor ergonomics; add context with.with_context(|| "doing X"). - Reserve
panic!for invariant violations the caller cannot recover from.
rust
#[derive(thiserror::Error, Debug)]pub enum LoadError {#[error("io: {0}")] Io(#[from] std::io::Error),#[error("bad format: {0}")] Format(String),}
Traits
- Design around capability, not identity (
Read, notIsFile). - Default methods let traits evolve without breaking implementors.
impl Traitin arguments → static dispatch, monomorphized, fast.dyn TraitbehindBox/&→ dynamic dispatch, smaller binary, one code path.- Choose
dynfor open-ended type sets or heterogeneous collections.
Iterators
Prefer iterator chains over indexed loops — usually faster, always clearer.
rust
let total: u32 = orders.iter().filter(|o| o.is_paid()).map(|o| o.total).sum();
collect::<Vec<_>>()only when you need to materialize.iter()borrows;into_iter()consumes;iter_mut()mutates in place.
Avoiding unnecessary clones
.clone()in a hot path is a red flag — can you borrow instead?Cow<'a, str>for "maybe owned, maybe borrowed" in APIs.Arc<T>for cheap shared ownership across threads;Rc<T>single-threaded.
Option and Result ergonomics
?propagates.ok_or_else,map_err,and_then,unwrap_or_else— chain, don't match.- Reserve
unwrap/expectfor truly unreachable cases; always preferexpect("why")overunwrapin production.
Doc comments
- rustdoc —
///doc comment: one summary line first;cargo docrenders it as the item's headline. - Add
# Examples,# Panics, or# Safetysections only when they apply, not as boilerplate.
rust
/// Returns the order total, excluding cancelled line items.pub fn total(&self) -> Decimal { ... }
Tooling
- Imports/Auto-fix:
cargo fix --allow-dirty(applies all auto-fixable rustc/Clippy lints — review the full diff before staging; not suitable as an unattended CI step) - Format:
cargo fmt(setimports_granularityinrustfmt.tomlfor import grouping;cargo fmt --checkin CI) - Lint:
cargo clippy -- -D warnings - Test:
cargo test(see Testing below)
Testing
#[cfg(test)] mod tests { ... }at the bottom of each file for unit tests.- Integration tests in
tests/. #[should_panic(expected = "...")]for panic paths.
Async
- Pick one runtime (usually
tokio) and stay there. async fnin traits —async-traitor the stable equivalent.Send + 'staticbounds propagate; design for them from the start.- Do not block in async —
spawn_blockingfor CPU or sync IO.
Avoid
unsafewithout a// SAFETY:comment explaining the invariant.- Reimplementing iterators imperatively.
Stringwhere&strwould do for read-only input.- Deep trait hierarchies — traits compose, they do not inherit.