rust-design-patterns
Skill4 starsChanged 3 months agoApache-2.0View on GitHub
Idiomatic Rust design patterns, idioms, and anti-patterns. Use when structuring Rust code, choosing between patterns like Newtype/Builder/Typestate, applying idioms like mem::take or borrowed-type arguments, or avoiding common anti-patterns.
We split this skill into the rules it gives an agent
2 rules. 0 are common, 0 are distinctive, and 2 are very specific to this project.
0
Common
Most of the 3 edited versions we read keep these.
0
Distinctive
This author's own choices. Worth a look.
2
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 22
Prefer &str over &String, &[T] over &Vec<T>, &T over &Box<T>:
- Very specific: line 175
Don't use Deref/DerefMut to simulate inheritance:
“Common” is measured: kept by at least 6 in 10 of the 3 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Rust Design Patterns
Based on Rust Design Patterns book, Effective Rust, and community idioms.
When to Use This Skill
- Structuring a new Rust module or crate
- Choosing the right abstraction pattern
- Avoiding common anti-patterns (Deref polymorphism, clone-to-satisfy-borrow-checker)
- Making APIs ergonomic and hard to misuse
- Encoding invariants in the type system
Idioms
Use Borrowed Types for Arguments
Prefer &str over &String, &[T] over &Vec<T>, &T over &Box<T>:
fn process(data: &str) { ... } // accepts &String, &str, String slice
fn sum(nums: &[i32]) { ... } // accepts &Vec<i32>, &[i32], arraysDefault Trait
#[derive(Default)]
struct Config {
port: u16, // 0
debug: bool, // false
name: String, // ""
}
let cfg = Config { port: 8080, ..Config::default() };mem::take / mem::replace
Move out of a &mut without clone:
use std::mem;
fn extract_name(user: &mut User) -> String {
mem::take(&mut user.name) // leaves empty String behind
}
// Replace with specific value
let old = mem::replace(&mut self.state, State::Done);Destructuring for Clarity
let Point { x, y } = point;
let (first, rest) = slice.split_first().unwrap();
// Ignore fields
let Config { port, .. } = config;Constructor Conventions
impl Connection {
pub fn new(addr: &str) -> Self { ... } // simple
pub fn builder() -> ConnectionBuilder { ... } // complex
pub fn with_timeout(addr: &str, ms: u64) -> Self { ... } // variant
}Design Patterns
Newtype
Wrap a type for type safety without runtime cost:
struct UserId(u64);
struct OrderId(u64);
// fn process(user: UserId, order: OrderId) — can't mix up argumentsAlso used to implement external traits on external types.
Builder
pub struct RequestBuilder {
url: String,
method: Method,
headers: Vec<(String, String)>,
timeout: Option<Duration>,
}
impl RequestBuilder {
pub fn new(url: impl Into<String>) -> Self { ... }
pub fn method(mut self, m: Method) -> Self { self.method = m; self }
pub fn header(mut self, k: impl Into<String>, v: impl Into<String>) -> Self { ... }
pub fn timeout(mut self, d: Duration) -> Self { self.timeout = Some(d); self }
pub fn build(self) -> Result<Request, BuildError> { ... }
}Typestate
Encode state machine transitions at compile time:
struct Tcp<S> { socket: RawFd, _state: PhantomData<S> }
struct Closed;
struct Connected;
struct Listening;
impl Tcp<Closed> {
fn connect(self, addr: &str) -> io::Result<Tcp<Connected>> { ... }
fn listen(self, port: u16) -> io::Result<Tcp<Listening>> { ... }
}
impl Tcp<Connected> {
fn send(&self, data: &[u8]) -> io::Result<usize> { ... }
fn close(self) -> Tcp<Closed> { ... }
}
impl Tcp<Listening> {
fn accept(&self) -> io::Result<Tcp<Connected>> { ... }
}
// Can't call .send() on a Closed socket — compile errorStrategy (via Trait Objects or Generics)
trait Compressor { fn compress(&self, data: &[u8]) -> Vec<u8>; }
struct Pipeline { compressor: Box<dyn Compressor> }
// or with generics:
struct Pipeline<C: Compressor> { compressor: C }Visitor
trait Visitor {
fn visit_file(&mut self, file: &File);
fn visit_dir(&mut self, dir: &Dir);
}
trait Visitable {
fn accept(&self, visitor: &mut dyn Visitor);
}RAII Guards
pub struct MutexGuard<'a, T> { lock: &'a Mutex<T> }
impl<T> Drop for MutexGuard<'_, T> {
fn drop(&mut self) { self.lock.release(); }
}
// Lock released automatically when guard goes out of scopeAnti-Patterns
Deref Polymorphism
Don't use Deref/DerefMut to simulate inheritance:
// BAD: using Deref to make Child act like Parent
impl Deref for Child { type Target = Parent; ... }
// GOOD: use composition + delegation or traits
struct Child { parent: Parent }
impl Child {
fn parent_method(&self) -> &str { self.parent.method() }
}Clone to Satisfy the Borrow Checker
// BAD: cloning just to avoid borrow conflicts
let key = map.keys().next().unwrap().clone();
map.remove(&key);
// GOOD: restructure control flow
if let Some(key) = map.keys().next().copied() {
map.remove(&key);
}Stringly Typed APIs
// BAD
fn set_color(color: &str) { ... }
// GOOD
enum Color { Red, Green, Blue, Custom(u8, u8, u8) }
fn set_color(color: Color) { ... }Reference Map
references/idioms.md— borrowed types, Default, mem::take, destructuringreferences/patterns.md— Newtype, Builder, Typestate, Visitor, RAIIreferences/anti-patterns.md— Deref polymorphism, clone-borrow, stringly-typed
Key References
Other versions3 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 3
- ahonn/dotfiles★ 62same name
- adxptived/Rust-Skills★ 1same name
- nledford/engineering-review-board★ 0same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository80 other files it gives its agents.
- a11y-accessibility-designSkill
- agentic-ui-patternsSkill
- ai-native-ui-designSkill
- ai-ui-anti-patternsSkill
- ai-ui-heuristicsSkill
- calm-technology-uiSkill
- conversion-growth-designSkill
- cross-platform-designSkill
- dark-mode-designSkill
- data-visualizationSkill
- design-systemsSkill
- design-thinking-processSkill
- error-empty-statesSkill
- ethical-design-patternsSkill
- form-uxSkill
- information-architectureSkill
- interaction-design-patternsSkill
- internationalization-uiSkill
- mobile-touch-designSkill
- modal-classes-lifecycleSkill
- modal-container-imagesSkill
- modal-dicts-queuesSkill
- modal-endpointsSkill
- modal-fundamentalsSkill
- modal-gpu-computeSkill
- modal-networkingSkill
- modal-observabilitySkill
- modal-parallel-executionSkill
- modal-sandboxesSkill
- modal-scaling-performanceSkill
- modal-schedulingSkill
- modal-secretsSkill
- modal-serversSkill
- modal-storageSkill
- modal-web-servingSkill
- modal-workspace-adminSkill
- motion-design-principlesSkill
- notifications-permissionsSkill
- onboarding-uxSkill
- rust-api-designSkill
- rust-async-programmingSkill
- rust-cargo-masterySkill
- rust-cli-applicationsSkill
- rust-clippy-lintsSkill
- rust-closures-iteratorsSkill
- rust-compiler-internalsSkill
- rust-concurrencySkill
- rust-editionsSkill
- rust-embeddedSkill
- rust-error-handlingSkill
- rust-game-developmentSkill
- rust-lifetimes-borrowingSkill
- rust-macrosSkill
- rust-performanceSkill
- rust-rustdocSkill
- rust-rustup-toolchainSkill
- rust-smart-pointersSkill
- rust-testing-benchmarkingSkill
- rust-type-systemSkill
- rust-unsafe-ffiSkill
- The first 60 shown.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

