| name | rust-quality |
| description | Review Rust code for idiomatic patterns, best practices, and production quality. Use when reviewing Rust crates, checking code quality, or before committing Rust changes. |
| allowed-tools | Read, Grep, Glob, Bash |
Rust Code Quality
Review skill for checking Rust code against idiomatic patterns and best practices.
Checklist
Error Handling
- Uses
thiserrorfor library errors,anyhowfor applications - No
.unwrap()or.expect()in production paths (use?operator) - Error types have meaningful context/payloads
-
Resultis returned, not panics - Uses
?operator, not.unwrap()chains
Ownership & Borrowing
- Prefers borrowing (
&T,&mut T) over cloning - Uses
Cloneonly when necessary - Avoids unnecessary
Arc/Rcwhen ownership transfer works - Lifetime annotations are minimal and correct
- No needless
to_string()/clone()in hot paths
Idiomatic Patterns
- Uses iterators over manual loops (
for i in 0..len→.iter()) - Uses
if let/matchfor Option/Result handling - Uses
?for early returns, not nestedif let - Prefers
impl Traitfor return types when appropriate - Uses builder pattern for complex construction
- Derives common traits:
Debug,Clone,Defaultwhere applicable
Naming Conventions (RFC 430)
- Types:
PascalCase - Functions/methods:
snake_case - Constants:
SCREAMING_SNAKE_CASE - Conversion methods:
as_*(cheap ref),to_*(expensive),into_*(ownership) - Getters: no
get_prefix (justfn name(&self)) - Predicates:
is_*,has_*,can_*
API Design
- Public items have doc comments (
///) - Examples in doc comments use
?notunwrap - Implements standard traits:
From,TryFrom,Default,Display - Uses newtypes for type safety (not raw primitives)
- Validates inputs at boundaries
- Functions take
impl Into<T>for flexible APIs
Async/Concurrency
- Uses
tokio::spawnfor fire-and-forget tasks - Channels sized appropriately (not unbounded without reason)
- No blocking in async contexts (use
spawn_blocking) - Mutex guards dropped before await points
- Uses
Arcfor shared ownership across threads
Performance
- Avoids allocations in hot paths
- Uses
&stroverStringfor borrowed data - Uses
Cow<str>when ownership is conditional - Prefers
Vec::with_capacitywhen size is known - Uses
#[inline]sparingly and intentionally
Project Structure
-
mod.rsormodule/mod.rspattern is consistent - Public API is re-exported cleanly from
lib.rs - Internal modules use
pub(crate)notpub - Tests in
tests/or#[cfg(test)]modules - Feature flags for optional dependencies
Clippy Lints
Run these checks:
cargo clippy -- -W clippy::pedantic -W clippy::nursery
cargo clippy -- -D clippy::unwrap_used -D clippy::expect_used
Key lint groups:
clippy::correctness- Must fix (deny by default)clippy::suspicious- Should fixclippy::style- Idiomatic codeclippy::complexity- Simplification opportunitiesclippy::perf- Performance improvementsclippy::pedantic- Extra strictness (recommended)
Common Anti-Patterns
Wrong
// Unnecessary clone
let name = self.name.clone();
do_something(&name);
// Unwrap in production
let value = map.get("key").unwrap();
// Manual loop
for i in 0..vec.len() {
process(vec[i]);
}
// Nested if-let
if let Some(x) = opt {
if let Ok(y) = x.parse() {
// ...
}
}
// Getter with get_ prefix
fn get_name(&self) -> &str { &self.name }
Right
// Borrow directly
do_something(&self.name);
// Handle error properly
let value = map.get("key").ok_or(MyError::KeyNotFound)?;
// Iterator
for item in &vec {
process(item);
}
// let-else or ? operator
let Some(x) = opt else { return None };
let y = x.parse()?;
// Clean getter
fn name(&self) -> &str { &self.name }
How to Use
- Run
cargo clippy -- -W clippy::pedanticfirst - Read the files to review
- Check against patterns above
- Report issues with
file:linereferences - Suggest idiomatic fixes