safe-rust
Safe Rust
Build highly predictable, robust, and performant Rust applications with strict adherence to ownership, lifetimes, and type-driven safety.
Retrieval-First Development
Always verify standards against the reference documentation before implementing.
| Resource | URL / Path |
|---|---|
| Memory & Safety | ./references/safety.md |
| Performance Patterns | ./references/performance.md |
| Developer Experience | ./references/dx.md |
Review the relevant documentation when writing new logic or performing code reviews.
When to Use
- Writing new Rust logic from scratch
- Refactoring existing Rust code to improve safety, performance, or idiomaticness
- Reviewing Rust PRs for code quality, borrow checker compliance, and standard adherence
- Optimizing memory allocations or hot paths
- Implementing strict error handling, type-state patterns, or zero-cost abstractions
Reference Documentation
./references/safety.md- Ownership, lifetimes, unsafe boundaries, error handling, unwrap/expect policies../references/performance.md- Allocation minimization,Cow, references vs. values, concurrency primitives../references/dx.md- Typestates, Newtype pattern, standard library traits (From,AsRef), Clippy lints.
Search: unwrap, unsafe, clippy::pedantic, Cow, Result, Rc, Arc, Mutex
Core Principles
Apply Safe Rust For
| Need | Example |
|---|---|
| Compile-Time Safety | Typestate pattern to prevent invalid state transitions |
| Memory Stability | Passing by reference (&T), reusing allocations, Cow<T> |
| Operational Reliability | Exhaustive pattern matching, Result over panic!, thiserror/anyhow |
| Maintainability | Implement From, TryFrom, AsRef, Display; document unsafe |
Do NOT Use
unwrap()orexpect()in production code (unless proving mathematically impossible to fail)unsafewithout a heavily documented// SAFETY:comment explaining invariants- Unnecessary
.clone()or allocations (String,Vec) in hot paths when&stror&[T]works Rc<RefCell<T>>orArc<Mutex<T>>as the first tool for state sharing (prefer structural borrowing or message passing)
Quick Reference
Typestate Pattern
// Use the type system to enforce valid state transitions at compile time
struct Unverified;
struct Verified;
struct Email<State> {
address: String,
_state: std::marker::PhantomData<State>,
}
impl Email<Unverified> {
fn new(address: String) -> Self {
Self { address, _state: std::marker::PhantomData }
}
fn verify(self) -> Result<Email<Verified>, &'static str> {
if self.address.contains('@') {
Ok(Email { address: self.address, _state: std::marker::PhantomData })
} else {
Err("Invalid email format")
}
}
}
// This function only accepts verified emails
fn send_welcome(email: &Email<Verified>) {
// ...
}
Allocation-Free Hot Path (Cow)
use std::borrow::Cow;
// Returns a reference if no changes needed, or an allocated String if modified
fn sanitize_input<'a>(input: &'a str) -> Cow<'a, str> {
if input.contains('\0') {
let mut cleaned = input.replace('\0', "");
Cow::Owned(cleaned)
} else {
Cow::Borrowed(input)
}
}
Critical Rules
- No Panics in Production - Avoid
unwrap(),expect(), array indexingarr[i](preferarr.get(i)). Handle all errors gracefully viaResultand?. - Minimal and Documented
unsafe- Ifunsafeis absolutely necessary for FFI or extreme performance, everyunsafeblock must be preceded by a// SAFETY: ...comment proving the invariants. - Minimize Allocations - Prefer passing
&T,&[T], and&stroverT,Vec<T>, andStringfor function arguments unless ownership is required. - Leverage the Type System - Use the Newtype pattern (e.g.,
struct UserId(u64)) to prevent unit confusion. Use typestates for state machines. - Strict Clippy Compliance - Treat
#![warn(clippy::pedantic)]as the baseline. Explicitly#[allow(...)]with comments if deviating. - Thread Safety via Message Passing or Ownership - Share state via channels (
mpscorcrossbeam) orArc<T>(read-only) rather than defaulting toArc<Mutex<T>>. - Idiomatic Traits - Implement standard traits like
Default,From,TryFrom,AsRef, andDisplayinstead of custom conversion/instantiation methods. - Error Types - Use
thiserrorfor library error types (to provide explicitenumvariants) andanyhowfor application entry points/handlers. - Zero-Cost Abstractions - Use generics and inline functions
#[inline]for hot paths to allow the compiler to optimize without runtime overhead. - Exhaustive Matches - Never use the wildcard
_in amatchstatement on anenumunless explicitly intending to ignore all future variants. Force the compiler to check exhaustiveness.
Anti-Patterns (NEVER)
- Sprinkling
.clone()to appease the borrow checker instead of fixing lifetimes/architecture. - Using
unsafejust to bypass borrow checker limitations without sound reasoning. - Catching panics (
catch_unwind) as a general error handling mechanism. - Storing references with complex lifetimes in structs when ownership makes more sense for API usability.
- Ignoring Clippy warnings without justification.
- Returning
StringorVecfrom parsing functions that could just return slices (&str,&[T]) borrowed from the input.
More from thedumptruck/skills
safe-ts
Enforce "safe-ts" coding principles in TypeScript. Use when writing, reading, reviewing, or refactoring TypeScript code to ensure maximum safety, predictable execution, and zero technical debt.
21safe-golang
Enforce "safe-golang" coding principles in Go. Use when writing, reading, reviewing, or refactoring Go code to ensure maximum safety, predictable execution, and zero technical debt.
17safe-c
Enforce "safe-c" coding principles in C. Based on TigerBeetle's Tiger Style. Use when writing, reading, reviewing, or refactoring C code to ensure maximum safety, predictable execution, zero technical debt, and extreme performance.
13