Agent skill
rust-coding-standards
Master Rust's ownership system, type safety, and zero-cost abstractions for building safe, concurrent, and performant systems. Covers borrowing, lifetimes, traits, error handling, async/await, and testing patterns.
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/development/rust-coding-standards
SKILL.md
Rust Coding Standards
Purpose: Master Rust's ownership system, type safety, and zero-cost abstractions for building safe, concurrent, and performant systems.
Level 1: Quick Reference
Core Principles
- Ownership: Each value has exactly one owner
- Borrowing: References allow multiple readers XOR one writer
- Zero-cost abstractions: High-level code compiles to optimal machine code
- Explicit over implicit: No hidden allocations or control flow
Ownership & Borrowing Cheat Sheet
// Ownership transfer (move)
let s1 = String::from("hello");
let s2 = s1; // s1 is now invalid
// Immutable borrow (multiple allowed)
let s = String::from("hello");
let r1 = &s;
let r2 = &s;
println!("{} and {}", r1, r2); // OK
// Mutable borrow (exclusive)
let mut s = String::from("hello");
let r1 = &mut s;
r1.push_str(" world");
// Copy types (stack-only)
let x = 5;
let y = x; // x is still valid (i32 implements Copy)
Result & Option
// Option: value may be absent
let name = find_user(42).map(|u| u.name).unwrap_or("Anonymous".into());
// Early return with ?
fn process() -> Result<(), Error> {
let config = parse_config("app.toml")?;
Ok(())
}
Essential Checklist
-
cargo clippy -- -D warnings -
cargo fmt -- --check -
cargo test -
cargo doc --no-deps -
cargo audit - Document all
unsafeblocks
Memory Safety Rules
- No data races: Compiler enforces at compile time
- No null pointers: Use
Option<T>instead - No dangling pointers: Borrow checker prevents
- No use-after-free: Ownership system prevents
- No buffer overflows: Bounds checking
Level 2: Implementation Guide
Ownership System
The Three Rules
- Each value has a variable that's its owner
- There can only be one owner at a time
- When the owner goes out of scope, the value is dropped
fn takes_ownership(s: String) {
println!("{}", s);
} // s dropped here
fn main() {
let s = String::from("hello");
takes_ownership(s); // s moved
// println!("{}", s); // Error: value borrowed after move
}
// Return ownership
fn gives_ownership() -> String {
String::from("hello")
}
Borrowing & References
// Multiple immutable borrows allowed
fn calculate_length(s: &String) -> usize {
s.len()
}
// Only one mutable borrow allowed
fn change(s: &mut String) {
s.push_str(", world");
}
// Non-lexical lifetimes
let mut s = String::from("hello");
let r1 = &s;
let r2 = &s;
println!("{} and {}", r1, r2); // last use of r1 and r2
let r3 = &mut s; // OK: r1 and r2 no longer used
Lifetime Annotations
// Specify reference relationships
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() { x } else { y }
}
// Struct with lifetime
struct Excerpt<'a> {
part: &'a str,
}
// Lifetime elision: compiler infers in common patterns
fn first_word(s: &str) -> &str { /* elided lifetimes */ }
Traits & Generics
pub trait Summary {
fn summarize(&self) -> String;
// Default implementation
fn full_summary(&self) -> String {
format!("Read more: {}", self.summarize())
}
}
impl Summary for Article {
fn summarize(&self) -> String {
format!("{} by {}", self.headline, self.author)
}
}
// Trait bounds
pub fn notify<T: Summary + Display>(item: &T) {
println!("Breaking: {}", item.summarize());
}
// where clause for readability
pub fn process<T, U>(t: &T, u: &U) -> String
where
T: Display + Clone,
U: Clone + Debug,
{
format!("{:?}", u)
}
Common Derived Traits
#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
pub struct User {
pub id: u32,
pub name: String,
}
Error Handling
use thiserror::Error;
#[derive(Error, Debug)]
pub enum AppError {
#[error("IO error: {0}")]
Io(#[from] std::io::Error),
#[error("Database error: {0}")]
Database(#[from] sqlx::Error),
#[error("Not found: {0}")]
NotFound(String),
}
pub type Result<T> = std::result::Result<T, AppError>;
// With anyhow for context
use anyhow::Context;
fn read_config() -> anyhow::Result<Config> {
let content = fs::read_to_string("config.toml")
.context("Failed to read config file")?;
Ok(toml::from_str(&content)?)
}
Async/Await
use tokio;
#[tokio::main]
async fn main() -> Result<()> {
let result = fetch_data().await?;
process(result).await?;
Ok(())
}
// Concurrent execution
let futures = urls.iter().map(|url| fetch_url(url));
let results = futures::future::join_all(futures).await;
// Spawn tasks
let handle = tokio::spawn(async move {
expensive_computation().await
});
let result = handle.await?;
Channels
use tokio::sync::mpsc;
let (tx, mut rx) = mpsc::channel(32);
// Producer
tokio::spawn(async move {
tx.send(work).await.unwrap();
});
// Consumer
while let Some(result) = rx.recv().await {
process(result).await;
}
Shared State
use std::sync::Arc;
use tokio::sync::{Mutex, RwLock};
#[derive(Clone)]
struct AppState {
counter: Arc<Mutex<u64>>,
cache: Arc<RwLock<HashMap<String, String>>>,
}
async fn increment(state: AppState) {
let mut counter = state.counter.lock().await;
*counter += 1;
}
Testing
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_basic() {
assert_eq!(2 + 2, 4);
}
#[test]
#[should_panic(expected = "divide by zero")]
fn test_panic() {
divide(10, 0);
}
#[test]
fn test_result() -> Result<()> {
let result = parse_number("42")?;
assert_eq!(result, 42);
Ok(())
}
#[tokio::test]
async fn test_async() {
let result = fetch_data().await;
assert!(result.is_ok());
}
}
Performance Patterns
// Prefer slices over owned strings
fn count_words(text: &str) -> usize {
text.split_whitespace().count()
}
// Use Cow for conditional cloning
use std::borrow::Cow;
fn process_text(text: &str) -> Cow<str> {
if text.contains("bad") {
Cow::Owned(text.replace("bad", "good"))
} else {
Cow::Borrowed(text)
}
}
// Reuse buffers
let mut buffer = String::with_capacity(1024);
for item in items {
buffer.clear();
write!(&mut buffer, "{}", item)?;
send(&buffer)?;
}
Iterators
// Transformation pipeline (zero-cost)
let sum: i32 = vec![1, 2, 3, 4, 5]
.iter()
.filter(|&x| x % 2 == 0)
.map(|x| x * 2)
.sum();
// Collect into different types
let doubled: Vec<i32> = numbers.iter().map(|x| x * 2).collect();
let set: HashSet<i32> = numbers.into_iter().collect();
Level 3: Deep Dive Resources
For comprehensive coverage of advanced topics, see REFERENCE.md:
Advanced Patterns
- Newtype Pattern: Type safety via wrapper types
- Typestate Pattern: Encode state machines in types
- Builder Pattern: Fluent API construction
Unsafe Code Guidelines
- Documenting safety invariants
- Minimizing unsafe scope
- Testing with Miri
Complete Examples
- Full async service implementation
- Property-based testing with proptest
- Mocking with mockall
- Integration test patterns
Configuration Files
config/rustfmt.toml- Formatter configurationconfig/clippy.toml- Linter rulestemplates/- Project templates
Performance Deep Dive
- Profiling with flamegraph
- Compiler optimization flags
- Memory profiling with valgrind
Learning Path
- Start: Rust Book
- Practice: Rustlings
- Patterns: Rust Design Patterns
- Async: Tokio Tutorial
Common Pitfalls
- Fighting the borrow checker - design with ownership in mind
- Over-using
.clone()- profile before optimizing - Ignoring Clippy warnings - they're usually right
- Not using
?operator - makes error handling cleaner - Premature unsafe - try safe abstractions first
- String vs &str confusion - prefer &str for parameters
Skill Complete: Comprehensive Rust coding standards covering ownership, traits, error handling, concurrency, testing, and performance. See REFERENCE.md for advanced patterns and complete examples.
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
Didn't find tool you were looking for?