Loading...
Loading...
Idiomatic Rust development with focus on safety, performance, and ergonomics. Expert in async/await, error handling, trait design, and the Rust ecosystem.
npx skill4agent add terraphim/terraphim-skills rust-development1. RUN -> Does it compile and execute?
2. TEST -> Does it produce correct results?
3. BENCH -> Is it fast enough?
Repeat this loop. Never optimize before proving correctness.# The workflow in practice
cargo build # 1. RUN - compile
cargo test # 2. TEST - verify correctness
cargo bench # 3. BENCH - measure performance (only after tests pass)project/
Cargo.toml # Workspace root
crates/
core/ # Core logic, no I/O
Cargo.toml
src/lib.rs
cli/ # CLI interface only
Cargo.toml
src/main.rs
io/ # I/O abstractions
Cargo.toml
src/lib.rs// Good: Minimal public API at boundary
pub mod parser {
mod lexer; // internal
mod ast; // internal
pub use ast::Ast;
pub fn parse(input: &str) -> Result<Ast, Error>;
}# Always use rustfmt defaults (Rust style guide)
cargo fmt --check # CI check
cargo fmt # Auto-format# CI: Treat warnings as errors via RUSTFLAGS (not code attributes)
RUSTFLAGS="-D warnings" cargo clippy --all-targets --all-features
# Local development
cargo clippy --all-targets --all-features#![deny(warnings)]// BAD: Breaks when new lints are added to Rust
#![deny(warnings)]
// GOOD: Explicit lint policy in Cargo.toml or CI
[lints.rust]
unsafe_code = "warn"
missing_docs = "warn"
[lints.clippy]
all = "deny"
pedantic = "warn"#[allow(clippy::too_many_arguments)]
// Justified: Builder pattern not suitable here because X, Y, Z
fn complex_initialization(/* many args */) { }// Take ownership when you need it
fn consume(value: String) -> Result<Output, Error> { ... }
// Borrow when you just need to read
fn inspect(value: &str) -> bool { ... }
// Borrow mutably for in-place modification
fn modify(value: &mut Vec<u8>) { ... }
// Use Cow for flexible ownership
fn process(value: Cow<'_, str>) -> String { ... }// Custom error types with thiserror
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("configuration error: {0}")]
Config(String),
#[error("I/O error")]
Io(#[from] std::io::Error),
#[error("parse error at line {line}: {message}")]
Parse { line: usize, message: String },
}
// Result type alias for convenience
pub type Result<T> = std::result::Result<T, Error>;pub struct Client {
config: Config,
}
impl Client {
pub fn builder() -> ClientBuilder {
ClientBuilder::default()
}
}
#[derive(Default)]
pub struct ClientBuilder {
timeout: Option<Duration>,
retries: Option<u32>,
}
impl ClientBuilder {
pub fn timeout(mut self, timeout: Duration) -> Self {
self.timeout = Some(timeout);
self
}
pub fn retries(mut self, retries: u32) -> Self {
self.retries = Some(retries);
self
}
pub fn build(self) -> Result<Client> {
Ok(Client {
config: Config {
timeout: self.timeout.unwrap_or(Duration::from_secs(30)),
retries: self.retries.unwrap_or(3),
},
})
}
}// Use extension traits for adding methods to foreign types
pub trait StringExt {
fn truncate_to(&self, max_len: usize) -> &str;
}
impl StringExt for str {
fn truncate_to(&self, max_len: usize) -> &str {
if self.len() <= max_len {
self
} else {
&self[..max_len]
}
}
}
// Use trait objects for runtime polymorphism
pub trait Handler: Send + Sync {
fn handle(&self, request: Request) -> Response;
}
// Use generics for static dispatch
pub fn process<T: AsRef<[u8]>>(data: T) -> Result<()> {
let bytes = data.as_ref();
// ...
}// Use async traits with async-trait crate (until native support)
#[async_trait]
pub trait Service {
async fn call(&self, request: Request) -> Response;
}
// Structured concurrency with tokio
async fn process_batch(items: Vec<Item>) -> Vec<Result<Output>> {
let futures: Vec<_> = items
.into_iter()
.map(|item| async move { process_item(item).await })
.collect();
futures::future::join_all(futures).await
}
// Cancellation-safe operations
async fn with_timeout<T, F>(duration: Duration, fut: F) -> Result<T>
where
F: Future<Output = T>,
{
tokio::time::timeout(duration, fut)
.await
.map_err(|_| Error::Timeout)
}| Category | Crate | Purpose |
|---|---|---|
| Async Runtime | tokio | Industry standard async runtime |
| Serialization | serde | De/serialization framework |
| HTTP Client | reqwest | Async HTTP client |
| HTTP Server | axum | Ergonomic web framework |
| CLI | clap | Command-line parsing |
| Logging | tracing | Structured logging/tracing |
| Error Handling | thiserror | Derive Error implementations |
| Error Context | anyhow | Application error handling |
| Testing | proptest | Property-based testing |
| Mocking | mockall | Mock generation |
clone()spawn_blocking/// SAFETY: This module provides safe wrappers around raw pointer operations.
/// All public functions maintain the following invariants:
/// - Pointers are always valid and aligned
/// - Lifetimes are correctly bounded
/// - No data races possible (single-threaded access enforced)
mod raw_buffer {
/// SAFETY: `ptr` must be valid for reads of `len` bytes.
/// The caller must ensure the memory is initialized.
/// This is verified by: unit tests, property tests, and fuzzing.
pub unsafe fn read_unchecked(ptr: *const u8, len: usize) -> Vec<u8> {
// implementation
}
}zerocopybytemuck#[cfg(test)]
mod tests {
use super::*;
#[test]
fn raw_buffer_valid_input() {
// Test the happy path
}
#[test]
fn raw_buffer_empty_input() {
// Edge case: zero length
}
// Property-based test to find edge cases
proptest! {
#[test]
fn raw_buffer_never_panics(data: Vec<u8>) {
// Should never panic or cause UB
}
}
}// BAD: Unhelpful error
Err(Error::Failed)
// GOOD: Actionable error with context
#[derive(Debug, thiserror::Error)]
pub enum ConfigError {
#[error("config file not found at {path}: run `app init` to create one")]
NotFound { path: PathBuf },
#[error("invalid config at {path}:{line}: {message}")]
Parse { path: PathBuf, line: usize, message: String },
#[error("permission denied reading {path}: check file permissions with `ls -la {path}`")]
PermissionDenied { path: PathBuf },
}thiserroranyhowunwrap()expect()unsafe#![deny(warnings)]RcRefCellcargo fmt --checkcargo clippy#[allow(...)]