Agent Skills Framework Extension
Rust Development Patterns Skill
When to Use This Skill
Use this skill when implementing rust development patterns patterns in your codebase.
How to Use This Skill
- Review the patterns and examples below
- Apply the relevant patterns to your implementation
- Follow the best practices outlined in this skill
Production Rust patterns for async programming, memory safety, and high-performance systems.
Core Capabilities
- Async Programming - Tokio runtime, async/await, concurrent patterns
- Memory Safety - Ownership, lifetimes, borrowing, zero-copy
- Error Handling - Result types, custom errors, error propagation
- Trait System - Generic programming, trait bounds, associated types
- Performance - Zero-cost abstractions, SIMD, cache efficiency
Async Web Service Pattern
// src/main.rs - Production async web service
use actix_web::{web, App, HttpServer, Result, middleware};
use sqlx::PgPool;
use std::sync::Arc;
use tokio::signal;
#[derive(Clone)]
pub struct AppState {
db: Arc<PgPool>,
config: Arc<AppConfig>,
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
tracing_subscriber::fmt::init();
let config = AppConfig::from_env().expect("Failed to load config");
let db = create_db_pool(&config.database_url).await
.expect("Failed to create database pool");
let app_state = AppState {
db: Arc::new(db),
config: Arc::new(config.clone()),
};
let server = HttpServer::new(move || {
App::new()
.app_data(web::Data::new(app_state.clone()))
.wrap(middleware::Logger::default())
.wrap(middleware::Compress::default())
.configure(configure_routes)
})
.bind(("0.0.0.0", config.port))?
.run();
tokio::select! {
res = server => res,
_ = signal::ctrl_c() => {
tracing::info!("Shutting down gracefully");
Ok(())
}
}
}
async fn create_db_pool(database_url: &str) -> Result<PgPool, sqlx::Error> {
sqlx::postgres::PgPoolOptions::new()
.max_connections(20)
.acquire_timeout(std::time::Duration::from_secs(30))
.connect(database_url)
.await
}
Advanced Error Handling
// src/errors.rs - Comprehensive error system
use thiserror::Error;
use actix_web::{ResponseError, HttpResponse, http::StatusCode};
use serde::Serialize;
#[derive(Error, Debug)]
pub enum AppError {
#[error("Database error: {0}")]
Database(#[from] sqlx::Error),
#[error("Validation error: {0}")]
Validation(String),
#[error("Not found: {entity_type} with id {id}")]
NotFound {
entity_type: String,
id: String,
},
#[error("Authentication error: {0}")]
Authentication(String),
#[error("Authorization error: user {user_id} cannot {action} {resource}")]
Authorization {
user_id: String,
action: String,
resource: String,
},
#[error("External service error: {0}")]
ExternalService(#[from] reqwest::Error),
#[error("Internal error")]
Internal(#[from] anyhow::Error),
}
#[derive(Serialize)]
struct ErrorResponse {
error: String,
message: String,
#[serde(skip_serializing_if = "Option::is_none")]
details: Option<serde_json::Value>,
}
impl ResponseError for AppError {
fn error_response(&self) -> HttpResponse {
let (status, error_type) = match self {
AppError::Validation(_) => (StatusCode::BAD_REQUEST, "validation_error"),
AppError::NotFound { .. } => (StatusCode::NOT_FOUND, "not_found"),
AppError::Authentication(_) => (StatusCode::UNAUTHORIZED, "authentication_error"),
AppError::Authorization { .. } => (StatusCode::FORBIDDEN, "authorization_error"),
AppError::Database(_) | AppError::Internal(_) =>
(StatusCode::INTERNAL_SERVER_ERROR, "internal_error"),
AppError::ExternalService(_) =>
(StatusCode::BAD_GATEWAY, "external_service_error"),
};
HttpResponse::build(status).json(ErrorResponse {
error: error_type.to_string(),
message: self.to_string(),
details: None,
})
}
fn status_code(&self) -> StatusCode {
match self {
AppError::Validation(_) => StatusCode::BAD_REQUEST,
AppError::NotFound { .. } => StatusCode::NOT_FOUND,
AppError::Authentication(_) => StatusCode::UNAUTHORIZED,
AppError::Authorization { .. } => StatusCode::FORBIDDEN,
_ => StatusCode::INTERNAL_SERVER_ERROR,
}
}
}
Repository Pattern with Traits
// src/repository.rs - Generic repository pattern
use async_trait::async_trait;
use sqlx::PgPool;
use uuid::Uuid;
use std::marker::PhantomData;
#[async_trait]
pub trait Repository<T>: Send + Sync {
async fn find_by_id(&self, id: Uuid) -> Result<Option<T>, AppError>;
async fn find_all(&self, limit: i64, offset: i64) -> Result<Vec<T>, AppError>;
async fn create(&self, entity: T) -> Result<T, AppError>;
async fn update(&self, id: Uuid, entity: T) -> Result<T, AppError>;
async fn delete(&self, id: Uuid) -> Result<bool, AppError>;
}
pub struct PostgresRepository<T> {
pool: Arc<PgPool>,
_phantom: PhantomData<T>,
}
impl<T> PostgresRepository<T> {
pub fn new(pool: Arc<PgPool>) -> Self {
Self {
pool,
_phantom: PhantomData,
}
}
}
#[async_trait]
impl Repository<User> for PostgresRepository<User> {
async fn find_by_id(&self, id: Uuid) -> Result<Option<User>, AppError> {
let user = sqlx::query_as!(
User,
"SELECT id, email, name, created_at FROM users WHERE id = $1",
id
)
.fetch_optional(&*self.pool)
.await?;
Ok(user)
}
async fn create(&self, user: User) -> Result<User, AppError> {
let created = sqlx::query_as!(
User,
r#"
INSERT INTO users (id, email, name, created_at)
VALUES ($1, $2, $3, NOW())
RETURNING id, email, name, created_at
"#,
user.id,
user.email,
user.name
)
.fetch_one(&*self.pool)
.await?;
Ok(created)
}
// ... other methods
}
Concurrent Stream Processing
// src/stream_processor.rs - High-performance async streams
use tokio_stream::{StreamExt, Stream};
use tokio::sync::mpsc;
use futures::stream::{FuturesUnordered, StreamExt as _};
pub struct StreamProcessor {
concurrency: usize,
}
impl StreamProcessor {
pub async fn process_batch<T, F, Fut, R>(
&self,
items: Vec<T>,
processor: F,
) -> Vec<Result<R, AppError>>
where
T: Send + 'static,
F: Fn(T) -> Fut + Send + Sync + Clone + 'static,
Fut: Future<Output = Result<R, AppError>> + Send,
R: Send + 'static,
{
let mut futures = FuturesUnordered::new();
for item in items {
let processor = processor.clone();
futures.push(tokio::spawn(async move {
processor(item).await
}));
}
let mut results = Vec::new();
while let Some(result) = futures.next().await {
match result {
Ok(res) => results.push(res),
Err(e) => results.push(Err(AppError::Internal(e.into()))),
}
}
results
}
pub async fn process_stream<S, T, F, Fut, R>(
&self,
stream: S,
processor: F,
) -> impl Stream<Item = Result<R, AppError>>
where
S: Stream<Item = T> + Send,
T: Send + 'static,
F: Fn(T) -> Fut + Send + Sync + Clone + 'static,
Fut: Future<Output = Result<R, AppError>> + Send,
R: Send + 'static,
{
stream
.map(move |item| {
let processor = processor.clone();
tokio::spawn(async move {
processor(item).await
})
})
.buffer_unordered(self.concurrency)
.map(|result| {
result.unwrap_or_else(|e| Err(AppError::Internal(e.into())))
})
}
}
Zero-Copy Optimization
// src/zero_copy.rs - Memory-efficient patterns
use bytes::{Bytes, BytesMut, BufMut};
use std::io::Write;
pub struct ZeroCopyBuffer {
inner: BytesMut,
}
impl ZeroCopyBuffer {
pub fn new() -> Self {
Self {
inner: BytesMut::with_capacity(4096),
}
}
pub fn write_slice(&mut self, data: &[u8]) {
self.inner.put_slice(data);
}
pub fn freeze(self) -> Bytes {
self.inner.freeze()
}
pub fn as_slice(&self) -> &[u8] {
&self.inner
}
}
// Avoid unnecessary allocations
pub fn process_large_file(path: &str) -> Result<Vec<String>, std::io::Error> {
use std::fs::File;
use std::io::{BufReader, BufRead};
let file = File::open(path)?;
let reader = BufReader::new(file);
// Process line-by-line without loading entire file
let mut results = Vec::new();
for line in reader.lines() {
let line = line?;
if line.starts_with("ERROR") {
results.push(line);
}
}
Ok(results)
}
Usage Examples
Async Web Service
Apply rust-development-patterns skill to create production Actix-web service with async handlers
Error Handling
Apply rust-development-patterns skill to implement comprehensive error system with custom types
Repository Pattern
Apply rust-development-patterns skill to design generic repository with async trait
Integration Points
- rust-qa-patterns - Testing strategies
- error-debugging-patterns - Error analysis
- cicd-automation-patterns - Build automation
Success Output
When successful, this skill MUST output:
✅ SKILL COMPLETE: rust-development-patterns
Completed:
- [x] Async runtime configured (Tokio/async-std)
- [x] Error handling implemented with custom error types
- [x] Memory safety verified (no unsafe blocks or documented justification)
- [x] Repository pattern implemented with traits
- [x] Zero-copy optimizations applied where appropriate
- [x] All code passes clippy with no warnings
- [x] Cargo.toml dependencies locked with specific versions
Outputs:
- src/*.rs files with async handlers
- Custom error types in src/errors.rs
- Repository traits in src/repository.rs
- Cargo.toml with dependency specifications
- clippy.toml configuration
Completion Checklist
Before marking this skill as complete, verify:
-
cargo build --releasecompletes without errors -
cargo clippy -- -D warningspasses with zero warnings -
cargo fmt --checkpasses (code is formatted) - All async functions use proper error propagation (? operator)
- Custom error types implement Error + Display + From traits
- No
unwrap()orexpect()in production code paths - Trait bounds are minimal and necessary
- Lifetimes are explicit only where needed
- Database connections use connection pooling
- Graceful shutdown implemented for async runtimes
Failure Indicators
This skill has FAILED if:
- ❌ Code contains unsafe blocks without safety documentation
- ❌ clippy warnings present (especially
clippy::unwrap_used) - ❌ Async runtime not configured properly (missing #[tokio::main])
- ❌ Error types don't implement proper trait bounds
- ❌ Memory leaks detected in long-running processes
- ❌ Blocking I/O in async context without spawn_blocking
- ❌ Database queries not using prepared statements/query macros
- ❌ No graceful shutdown handling (SIGTERM/SIGINT)
- ❌ Dependencies using wildcard versions (*) in Cargo.toml
When NOT to Use
Do NOT use this skill when:
- Writing Python/JavaScript/Go services (use language-specific patterns)
- Building simple CLI tools without async requirements (skip Tokio complexity)
- Prototyping without production requirements (Python/Node.js faster for POCs)
- Working with embedded systems requiring no_std (use
embedded-rust-patterns) - Building WebAssembly modules only (use
wasm-rust-patterns) - Creating FFI bindings to C libraries (use
rust-ffi-patterns) - Learning Rust basics (start with simpler synchronous patterns first)
Anti-Patterns (Avoid)
| Anti-Pattern | Problem | Solution |
|---|---|---|
Using .unwrap() in production | Panics crash entire process | Use ? operator and proper error handling |
| Cloning unnecessarily | Performance overhead | Use references (&) and lifetimes |
| String concatenation in loops | O(n²) allocations | Use format!() or String::with_capacity() |
| Blocking I/O in async context | Blocks entire runtime thread | Use spawn_blocking() for blocking calls |
| Not using type aliases | Verbose generic types | Create type aliases for complex generics |
| Ignoring Clippy warnings | Misses Rust best practices | Fix all warnings before production |
| Overly complex lifetimes | Hard to maintain | Simplify with owned types or refactor |
| Not using match exhaustiveness | Runtime errors missed | Enable all match arms, use _ carefully |
Principles
This skill embodies:
- #2 First Principles - Rust ownership, borrowing, and lifetime principles
- #3 Keep It Simple - Zero-cost abstractions, no unnecessary complexity
- #4 Separation of Concerns - Trait-based architecture, repository pattern
- #5 Eliminate Ambiguity - Explicit error types, type safety
- #9 Self-Documenting - Rust's type system documents intent
- #10 Quality Over Speed - Memory safety and correctness first
Full Principles: CODITECT-STANDARD-AUTOMATION.md