← Back to list

rust-development
by trash-panda-v91-beta
A modular and declarative dotfiles configuration using Nix Flakes, Home Manager, and nix-darwin.
⭐ 1🍴 0📅 Jan 22, 2026
SKILL.md
name: rust-development description: Use when writing Rust code for memory safety, performance, and systems programming
Rust Development
Guidelines for safe, performant, and idiomatic Rust code.
When to Use
- Writing new Rust modules or crates
- Refactoring Rust code
- Systems programming tasks
- Performance-critical components
- Concurrent/parallel programming
Core Principles
- Memory Safety - Leverage ownership system for zero-cost safety
- Performance - Zero-cost abstractions and efficient code
- Fearless Concurrency - Safe parallel programming
- Explicit Error Handling - Use Result<T, E> and Option
- Idiomatic Patterns - Follow Rust conventions
Ownership and Borrowing
Basic Ownership Rules
// Rule 1: Each value has a single owner
let s1 = String::from("hello");
let s2 = s1; // s1 is moved, no longer valid
// Rule 2: Use references to borrow without taking ownership
fn calculate_length(s: &String) -> usize {
s.len()
} // s goes out of scope but doesn't own the data
// Rule 3: Mutable references are exclusive
let mut s = String::from("hello");
let r1 = &mut s;
// let r2 = &mut s; // ❌ Cannot have two mutable references
Borrowing Patterns
// Immutable borrows (multiple allowed)
let s = String::from("hello");
let r1 = &s;
let r2 = &s; // ✅ Multiple immutable borrows OK
// Mutable borrow (exclusive access)
let mut s = String::from("hello");
{
let r1 = &mut s;
r1.push_str(", world");
} // r1 goes out of scope
println!("{}", s); // ✅ Can use s again
Error Handling
Result<T, E> Pattern
use std::fs::File;
use std::io::Read;
// ❌ Don't use unwrap() in production
fn read_file_bad(path: &str) -> String {
let mut file = File::open(path).unwrap(); // Panics on error
let mut contents = String::new();
file.read_to_string(&mut contents).unwrap();
contents
}
// ✅ Proper error handling
fn read_file_good(path: &str) -> Result<String, std::io::Error> {
let mut file = File::open(path)?; // ? operator for early return
let mut contents = String::new();
file.read_to_string(&mut contents)?;
Ok(contents)
}
// ✅ Custom error types
#[derive(Debug)]
enum ConfigError {
Io(std::io::Error),
Parse(String),
}
impl From<std::io::Error> for ConfigError {
fn from(err: std::io::Error) -> Self {
ConfigError::Io(err)
}
}
Option Pattern
// ✅ Safe option handling
fn find_user(id: u32) -> Option<User> {
// Implementation
}
match find_user(123) {
Some(user) => println!("Found: {}", user.name),
None => println!("User not found"),
}
// ✅ Combinators for transformation
let user_name = find_user(123)
.map(|user| user.name)
.unwrap_or_else(|| "Unknown".to_string());
Memory Management
Smart Pointers
use std::rc::Rc;
use std::sync::Arc;
use std::cell::RefCell;
// Reference counting for shared ownership
let data = Rc::new(vec![1, 2, 3]);
let data_clone = Rc::clone(&data); // Increment reference count
// Thread-safe reference counting
let shared_data = Arc::new(vec![1, 2, 3]);
let thread_data = Arc::clone(&shared_data);
// Interior mutability pattern
let data = RefCell::new(vec![1, 2, 3]);
data.borrow_mut().push(4); // Runtime borrow checking
Lifetimes
// ✅ Explicit lifetime annotations
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() {
x
} else {
y
}
}
// ✅ Struct with lifetime
struct ImportantExcerpt<'a> {
part: &'a str,
}
impl<'a> ImportantExcerpt<'a> {
fn level(&self) -> i32 {
3
}
}
Concurrency and Parallelism
Thread Safety
use std::sync::{Arc, Mutex};
use std::thread;
// ✅ Shared mutable state with Arc<Mutex<T>>
let counter = Arc::new(Mutex::new(0));
let mut handles = vec![];
for _ in 0..10 {
let counter = Arc::clone(&counter);
let handle = thread::spawn(move || {
let mut num = counter.lock().unwrap();
*num += 1;
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
Async/Await
use tokio;
// ✅ Async function
async fn fetch_data(url: &str) -> Result<String, reqwest::Error> {
let response = reqwest::get(url).await?;
let body = response.text().await?;
Ok(body)
}
// ✅ Concurrent async operations
async fn fetch_multiple() -> Result<Vec<String>, Box<dyn std::error::Error>> {
let urls = vec!["https://api1.com", "https://api2.com"];
let futures: Vec<_> = urls
.iter()
.map(|&url| fetch_data(url))
.collect();
let results = futures::future::try_join_all(futures).await?;
Ok(results)
}
Performance Optimization
Zero-Cost Abstractions
// ✅ Iterator chains are zero-cost
let sum: i32 = (0..1_000_000)
.filter(|x| x % 2 == 0)
.map(|x| x * x)
.sum();
// ✅ Avoid unnecessary allocations
fn process_data(data: &[u8]) -> Vec<u8> {
data.iter()
.copied()
.filter(|&b| b > 0)
.collect()
}
Memory Efficiency
// ✅ Use slices instead of Vec when possible
fn analyze_data(data: &[f64]) -> f64 {
data.iter().sum::<f64>() / data.len() as f64
}
// ✅ Use Box for large stack data
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
ChangeColor(Box<[u8; 1024]>), // Box large arrays
}
Testing
Unit Tests
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_calculation() {
let result = calculate(2, 2);
assert_eq!(result, 4);
}
#[test]
#[should_panic(expected = "divide by zero")]
fn test_divide_by_zero() {
divide(10, 0);
}
#[test]
fn test_result_handling() -> Result<(), Box<dyn std::error::Error>> {
let result = risky_operation()?;
assert_eq!(result, "success");
Ok(())
}
}
Property-Based Testing
use quickcheck::quickcheck;
#[quickcheck]
fn prop_reverse_involutive(xs: Vec<u32>) -> bool {
let reversed: Vec<_> = xs.iter().rev().rev().cloned().collect();
xs == reversed
}
Best Practices Checklist
- Use
cargo clippyfor linting - Run
cargo fmtfor formatting - Handle all Result/Option cases explicitly
- Prefer borrowing over taking ownership
- Use iterators over manual loops
- Implement proper Error types for libraries
- Add comprehensive documentation with
/// - Use
#[deny(missing_docs)]for public APIs - Profile with
cargo flamegraphfor performance - Test with
cargo testand property-based tests
Common Patterns
Builder Pattern
pub struct Config {
host: String,
port: u16,
timeout: Duration,
}
pub struct ConfigBuilder {
host: Option<String>,
port: Option<u16>,
timeout: Option<Duration>,
}
impl ConfigBuilder {
pub fn new() -> Self {
Self {
host: None,
port: None,
timeout: None,
}
}
pub fn host(mut self, host: impl Into<String>) -> Self {
self.host = Some(host.into());
self
}
pub fn port(mut self, port: u16) -> Self {
self.port = Some(port);
self
}
pub fn build(self) -> Result<Config, String> {
Ok(Config {
host: self.host.ok_or("host is required")?,
port: self.port.unwrap_or(8080),
timeout: self.timeout.unwrap_or(Duration::from_secs(30)),
})
}
}
State Machine with Types
pub struct Pending;
pub struct Running;
pub struct Completed;
pub struct Task<State = Pending> {
id: u32,
_state: PhantomData<State>,
}
impl Task<Pending> {
pub fn new(id: u32) -> Self {
Task {
id,
_state: PhantomData,
}
}
pub fn start(self) -> Task<Running> {
Task {
id: self.id,
_state: PhantomData,
}
}
}
impl Task<Running> {
pub fn complete(self) -> Task<Completed> {
Task {
id: self.id,
_state: PhantomData,
}
}
}
Anti-Patterns to Avoid
Don't Fight the Borrow Checker
// ❌ Over-using Clone to avoid borrowing issues
fn bad_example(data: Vec<String>) -> Vec<String> {
data.clone() // Unnecessary allocation
}
// ✅ Work with borrowing
fn good_example(data: &[String]) -> Vec<&str> {
data.iter().map(|s| s.as_str()).collect()
}
Don't Overuse unwrap()
// ❌ Panic-prone code
let value = risky_operation().unwrap();
// ✅ Handle errors properly
let value = risky_operation().unwrap_or_else(|e| {
eprintln!("Operation failed: {}", e);
default_value()
});
Tooling Commands
# Create new project
cargo new myproject
cargo new mylib --lib
# Check without building
cargo check
# Lint and fix
cargo clippy
cargo clippy -- -W clippy::pedantic
# Format code
cargo fmt
# Run tests
cargo test
cargo test --release
# Benchmark
cargo bench
# Documentation
cargo doc --open
# Profile
cargo install flamegraph
cargo flamegraph --bin mybin
Performance Debugging
# Compile with optimizations
cargo build --release
# Profile binary size
cargo bloat --release
# Check assembly output
cargo asm myfunction --release
# Memory profiling
valgrind ./target/release/mybin
Remember
The compiler is your friend. When fighting the borrow checker, step back and consider if your design could be improved rather than working around the constraints.
Score
Total Score
55/100
Based on repository quality metrics
✓SKILL.md
SKILL.mdファイルが含まれている
+20
○LICENSE
ライセンスが設定されている
0/10
○説明文
100文字以上の説明がある
0/10
○人気
GitHub Stars 100以上
0/15
✓最近の活動
1ヶ月以内に更新
+10
○フォーク
10回以上フォークされている
0/5
✓Issue管理
オープンIssueが50未満
+5
✓言語
プログラミング言語が設定されている
+5
✓タグ
1つ以上のタグが設定されている
+5
Reviews
💬
Reviews coming soon


