| name | Rust |
| description | Rust development best practices and patterns. USE WHEN writing Rust code, designing Rust projects, working with Cargo, testing, or Rust package development. |
Rust Development Best Practices
Purpose
Guide Rust development following official standards, community best practices, and idiomatic patterns from The Rust Book, Rust API Guidelines, and the Rust team's recommendations.
Context Detection
This skill activates when:
- Claude is asked to work on Rust code
- Current directory path or git repository contains
Cargo.toml
- User is working with
.rs files
- Commands like
cargo, rustc, or clippy are mentioned
Workflow Routing
When executing a workflow, output this notification directly:
Running the **WorkflowName** workflow from the **Rust** skill...
| Workflow | Trigger | File |
|---|
| Build | "build rust project", "cargo build", "compile" | workflows/Build.md |
| Test | "run tests", "cargo test", "test coverage" | workflows/Test.md |
| Bench | "benchmark", "cargo bench", "performance test" | workflows/Bench.md |
| Lint | "lint", "clippy", "cargo fmt", "format" | workflows/Lint.md |
| Deps | "dependencies", "cargo add", "update deps" | workflows/Deps.md |
| Error | "error handling", "Result", "thiserror", "anyhow" | workflows/Error.md |
| Workspace | "workspace", "multi-crate", "monorepo" | workflows/Workspace.md |
| Publish | "publish crate", "crates.io", "cargo publish" | workflows/Publish.md |
Core Principles
- Safety first: Leverage Rust's ownership and type system for memory safety
- Zero-cost abstractions: Write high-level code without runtime overhead
- Fearless concurrency: Use Rust's guarantees to write concurrent code safely
- Explicit error handling: Use
Result and Option types, never panic in libraries
- Idiomatic patterns: Follow Rust API Guidelines and community conventions
Standard Project Structure
Binary Application
myapp/
├── Cargo.toml # Project manifest
├── Cargo.lock # Dependency lock file (commit for apps)
├── src/
│ ├── main.rs # Entry point
│ ├── lib.rs # Optional library code
│ └── bin/ # Additional binaries
│ └── helper.rs
├── tests/ # Integration tests
│ └── integration_test.rs
├── benches/ # Benchmarks
│ └── my_bench.rs
├── examples/ # Example code
│ └── basic.rs
└── README.md
Library Crate
mylib/
├── Cargo.toml
├── Cargo.lock # Don't commit for libraries
├── src/
│ ├── lib.rs # Library root
│ └── submodule/
│ └── mod.rs
├── tests/
│ └── integration_test.rs
├── benches/
│ └── benchmark.rs
└── examples/
└── usage.rs
Workspace (Multiple Crates)
myworkspace/
├── Cargo.toml # Workspace manifest
├── Cargo.lock # Shared lock file
├── crates/
│ ├── core/
│ │ ├── Cargo.toml
│ │ └── src/lib.rs
│ ├── cli/
│ │ ├── Cargo.toml
│ │ └── src/main.rs
│ └── api/
│ ├── Cargo.toml
│ └── src/lib.rs
└── README.md
Writing Idiomatic Rust
Naming Conventions
struct MyStruct;
enum MyEnum { VariantA, VariantB }
trait MyTrait {}
fn my_function() {}
let my_variable = 42;
mod my_module {}
const MAX_SIZE: usize = 100;
static GLOBAL_COUNT: AtomicUsize = AtomicUsize::new(0);
fn foo<'a, 'b>(x: &'a str, y: &'b str) -> &'a str { x }
Error Handling
use std::fs::File;
use std::io::{self, Read};
fn read_file(path: &str) -> Result<String, io::Error> {
let mut file = File::open(path)?;
let mut contents = String::new();
file.read_to_string(&mut contents)?;
Ok(contents)
}
fn find_user(id: u64) -> Option<User> {
DATABASE.get(&id).cloned()
}
fn bad_read_file(path: &str) -> String {
let mut file = File::open(path).unwrap();
}
use thiserror::Error;
#[derive(Error, Debug)]
pub enum MyError {
#[error("IO error: {0}")]
Io(#[from] io::Error),
#[error("Parse error: {0}")]
Parse(String),
#[error("Not found: {0}")]
NotFound(String),
}
use anyhow::{Context, Result};
fn process_file(path: &str) -> Result<()> {
let contents = std::fs::read_to_string(path)
.context("Failed to read configuration file")?;
let config: Config = serde_json::from_str(&contents)
.context("Failed to parse JSON config")?;
Ok(())
}
Ownership and Borrowing
fn calculate_length(s: &String) -> usize {
s.len()
}
fn append_world(s: &mut String) {
s.push_str(", world!");
}
fn consume_string(s: String) -> usize {
s.len()
}
fn first_word(s: &str) -> &str {
let bytes = s.as_bytes();
for (i, &byte) in bytes.iter().enumerate() {
if byte == b' ' {
return &s[..i];
}
}
&s[..]
}
Iterator Patterns
let numbers: Vec<i32> = vec![1, 2, 3, 4, 5];
let doubled: Vec<i32> = numbers
.iter()
.map(|x| x * 2)
.collect();
let sum: i32 = numbers
.iter()
.filter(|&&x| x % 2 == 0)
.sum();
let result: Vec<String> = input
.lines()
.map(str::trim)
.filter(|line| !line.is_empty())
.map(|line| line.to_uppercase())
.collect();
let pairs: Vec<(usize, &i32)> = numbers
.iter()
.enumerate()
.filter(|(i, _)| i % 2 == 0)
.collect();
Cargo Essentials
Cargo.toml Configuration
[package]
name = "myproject"
version = "0.1.0"
edition = "2021"
rust-version = "1.70"
authors = ["Your Name <you@example.com>"]
description = "A short description"
documentation = "https://docs.rs/myproject"
repository = "https://github.com/user/myproject"
license = "MIT OR Apache-2.0"
keywords = ["cli", "tool"]
categories = ["command-line-utilities"]
[dependencies]
serde = { version = "1.0", features = ["derive"] }
tokio = { version = "1.0", features = ["full"] }
anyhow = "1.0"
[dev-dependencies]
criterion = "0.7"
proptest = "1.0"
[build-dependencies]
cc = "1.0"
[profile.release]
lto = true
codegen-units = 1
strip = true
opt-level = 3
[profile.dev]
opt-level = 0
debug = true
[workspace.dependencies]
serde = "1.0"
tokio = "1.0"
Common Commands
cargo new myproject
cargo new --lib mylib
cargo build
cargo build --release
cargo build --all-features
cargo run
cargo run --example basic
cargo test
cargo test --doc
cargo test integration
cargo check
cargo clippy
cargo fmt
cargo doc --open
cargo add serde
cargo update
cargo tree
Testing
Unit Tests
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_addition() {
assert_eq!(add(2, 2), 4);
}
#[test]
fn test_with_result() -> Result<(), String> {
if add(2, 2) == 4 {
Ok(())
} else {
Err(String::from("Addition failed"))
}
}
#[test]
#[should_panic(expected = "divided by zero")]
fn test_panic() {
divide(10, 0);
}
#[test]
#[ignore]
fn expensive_test() {
}
}
Integration Tests
use mylib;
#[test]
fn it_works() {
assert_eq!(mylib::add(2, 2), 4);
}
#[test]
fn test_full_workflow() {
let result = mylib::process_data("input.txt");
assert!(result.is_ok());
}
Property-Based Testing
use proptest::prelude::*;
proptest! {
#[test]
fn test_reversing_twice_gives_original(s in ".*") {
let reversed = reverse(&s);
let double_reversed = reverse(&reversed);
prop_assert_eq!(s, double_reversed);
}
#[test]
fn test_addition_commutative(a in 0..1000i32, b in 0..1000i32) {
prop_assert_eq!(a + b, b + a);
}
}
Async Rust with Tokio
use tokio;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let handle = tokio::spawn(async {
fetch_data().await
});
let result = handle.await?;
Ok(())
}
async fn fetch_data() -> Result<String, reqwest::Error> {
let response = reqwest::get("https://api.example.com/data")
.await?
.text()
.await?;
Ok(response)
}
use tokio::join;
async fn do_stuff_concurrently() {
let (result1, result2, result3) = join!(
fetch_thing_1(),
fetch_thing_2(),
fetch_thing_3()
);
}
Best Practices Checklist
Resources
Official Documentation
Error Handling
Testing & Benchmarking
Best Practices
Examples
Example 1: Creating a Rust CLI application
User: "Build a CLI tool to process logs"
→ Initializes project with cargo new
→ Adds clap for argument parsing
→ Implements error handling with anyhow
→ Writes unit tests and integration tests
→ Builds optimized binary with cargo build --release
→ Result: Fast, safe Rust CLI tool
Example 2: Fixing ownership and borrowing issues
User: "Help me fix these borrow checker errors"
→ Analyzes ownership flow in code
→ Identifies unnecessary clones or moves
→ Suggests lifetime annotations where needed
→ Refactors to use references appropriately
→ Explains Rust's ownership rules
→ Result: Clean code that satisfies the borrow checker
Example 3: Optimizing Rust performance
User: "This Rust code is slower than expected"
→ Uses cargo flamegraph to profile
→ Identifies allocations and hot paths
→ Optimizes with iterators and zero-copy operations
→ Adds benchmark tests with criterion
→ Measures improvement
→ Result: Performant Rust code with benchmarks