Rust Quality - Quick Reference
When NOT to Use This Skill
-
SonarQube setup - Use sonarqube skill
-
Security scanning - Use rust-security skill
Deep Knowledge: Use mcp__documentation__fetch_docs with technology: rust for comprehensive documentation.
Tool Overview
Tool Focus Command
rustfmt Formatting cargo fmt
Clippy Linting cargo clippy
rust-analyzer IDE analysis LSP
cargo-deny Dependency policy cargo deny
cargo-audit Security audit cargo audit
Clippy Setup
Run Clippy
Basic check
cargo clippy
Strict mode - deny all warnings
cargo clippy -- -D warnings
With pedantic lints
cargo clippy -- -W clippy::pedantic
Fix auto-fixable
cargo clippy --fix
All targets (tests, benches, examples)
cargo clippy --all-targets --all-features
clippy.toml
Maximum cognitive complexity
cognitive-complexity-threshold = 15
Maximum function length
too-many-lines-threshold = 50
Maximum arguments
too-many-arguments-threshold = 5
Allowed wildcard imports
allowed-wildcard-imports = ["crate::prelude::*"]
Cargo.toml Lint Configuration
[lints.rust] unsafe_code = "deny" missing_docs = "warn"
[lints.clippy]
Categories
pedantic = { level = "warn", priority = -1 } nursery = { level = "warn", priority = -1 }
Specific lints
unwrap_used = "warn" expect_used = "warn" panic = "warn" todo = "warn" dbg_macro = "warn"
Allow specific pedantic lints
module_name_repetitions = "allow" must_use_candidate = "allow"
CI Configuration
Strict CI check
cargo clippy --all-targets --all-features --
-D warnings
-D clippy::pedantic
-D clippy::nursery
-A clippy::module_name_repetitions
rustfmt Setup
rustfmt.toml
edition = "2021" max_width = 100 tab_spaces = 4 newline_style = "Unix"
Imports
imports_granularity = "Module" group_imports = "StdExternalCrate" reorder_imports = true
Items
reorder_modules = true reorder_impl_items = true
Formatting
use_small_heuristics = "Default" fn_single_line = false where_single_line = false struct_lit_single_line = true
Comments
comment_width = 100 wrap_comments = true normalize_comments = true
Macros
format_macro_matchers = true format_macro_bodies = true
Commands
Format all
cargo fmt
Check without changing
cargo fmt -- --check
Format specific file
rustfmt src/main.rs
Common Clippy Lints
unwrap_used / expect_used
// BAD - Panics on None/Err let value = some_option.unwrap(); let result = some_result.expect("should work");
// GOOD - Handle errors properly let value = some_option.ok_or(MyError::NotFound)?; let result = some_result.map_err(|e| MyError::from(e))?;
// GOOD - When panic is intentional (with justification) let value = config.get("required_key") .expect("required_key must be set in configuration");
clone_on_ref_ptr
// BAD - Cloning Arc/Rc unnecessarily let clone = arc_value.clone();
// GOOD - Use Arc::clone for clarity let clone = Arc::clone(&arc_value);
needless_pass_by_value
// BAD - Takes ownership unnecessarily fn process(data: String) { println!("{}", data); }
// GOOD - Borrow instead fn process(data: &str) { println!("{}", data); }
cognitive_complexity
// BAD - Too complex fn process(data: &Data) -> Result<Output, Error> { if data.is_valid() { if data.type_a() { if data.has_value() { // deep nesting... } } } // ... more conditions }
// GOOD - Extract and simplify fn process(data: &Data) -> Result<Output, Error> { validate(data)?;
match data.data_type() {
DataType::A => process_type_a(data),
DataType::B => process_type_b(data),
}
}
missing_errors_doc
// BAD - No error documentation /// Processes the data. pub fn process(data: &Data) -> Result<Output, Error> { ... }
// GOOD - Document errors
/// Processes the data.
///
/// # Errors
///
/// Returns Error::InvalidData if the data is malformed.
/// Returns Error::NotFound if the resource doesn't exist.
pub fn process(data: &Data) -> Result<Output, Error> { ... }
Common Code Smells & Fixes
- Stringly Typed Code
// BAD - Using strings for types fn set_status(status: &str) { match status { "active" => { ... } "inactive" => { ... } _ => panic!("unknown status"), } }
// GOOD - Use enums #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Status { Active, Inactive, }
fn set_status(status: Status) { match status { Status::Active => { ... } Status::Inactive => { ... } } }
- Error Handling
// BAD - Using unwrap in library code pub fn parse_config(path: &Path) -> Config { let content = fs::read_to_string(path).unwrap(); serde_json::from_str(&content).unwrap() }
// GOOD - Proper error handling with thiserror #[derive(Debug, thiserror::Error)] pub enum ConfigError { #[error("failed to read config file: {0}")] Io(#[from] std::io::Error), #[error("failed to parse config: {0}")] Parse(#[from] serde_json::Error), }
pub fn parse_config(path: &Path) -> Result<Config, ConfigError> { let content = fs::read_to_string(path)?; let config = serde_json::from_str(&content)?; Ok(config) }
- Builder Pattern
// BAD - Constructor with many parameters impl Server { pub fn new( host: String, port: u16, max_connections: usize, timeout: Duration, tls_config: Option<TlsConfig>, ) -> Self { ... } }
// GOOD - Builder pattern #[derive(Default)] pub struct ServerBuilder { host: String, port: u16, max_connections: usize, timeout: Duration, tls_config: Option<TlsConfig>, }
impl ServerBuilder { pub fn host(mut self, host: impl Into<String>) -> Self { self.host = host.into(); self }
pub fn port(mut self, port: u16) -> Self {
self.port = port;
self
}
pub fn build(self) -> Result<Server, BuildError> {
// Validate and build
}
}
// Usage let server = Server::builder() .host("localhost") .port(8080) .build()?;
- Newtype Pattern
// BAD - Primitive obsession fn create_user(email: String, name: String, age: u32) { ... }
// GOOD - Newtypes for validation #[derive(Debug, Clone)] pub struct Email(String);
impl Email { pub fn new(value: impl Into<String>) -> Result<Self, ValidationError> { let value = value.into(); if !value.contains('@') { return Err(ValidationError::InvalidEmail); } Ok(Self(value)) }
pub fn as_str(&self) -> &str {
&self.0
}
}
fn create_user(email: Email, name: Name, age: Age) { ... }
- Avoid clone() Abuse
// BAD - Cloning everywhere fn process(data: &Vec<Item>) { let owned = data.clone(); for item in owned { // process } }
// GOOD - Borrow when possible fn process(data: &[Item]) { for item in data { // process } }
// GOOD - Take ownership when needed fn process(data: Vec<Item>) { for item in data { // consume item } }
Pre-commit Setup
.pre-commit-config.yaml
repos:
- repo: local
hooks:
-
id: cargo-fmt name: cargo fmt entry: cargo fmt -- language: system types: [rust]
-
id: cargo-clippy name: cargo clippy entry: cargo clippy --all-targets --all-features -- -D warnings language: system types: [rust] pass_filenames: false
-
id: cargo-test name: cargo test entry: cargo test language: system types: [rust] pass_filenames: false
-
Makefile
.PHONY: fmt lint test check quality
fmt: cargo fmt
lint: cargo clippy --all-targets --all-features -- -D warnings
test: cargo test
check: cargo check --all-targets --all-features
quality: fmt check lint test
VS Code Settings
// .vscode/settings.json { "[rust]": { "editor.defaultFormatter": "rust-lang.rust-analyzer", "editor.formatOnSave": true }, "rust-analyzer.check.command": "clippy", "rust-analyzer.check.extraArgs": ["--all-targets", "--all-features"], "rust-analyzer.diagnostics.disabled": [], "rust-analyzer.lens.run.enable": true, "rust-analyzer.lens.debug.enable": true }
Quality Metrics Targets
Metric Target Tool
Cognitive Complexity < 15 Clippy
Function Lines < 50 Clippy
Arguments < 5 Clippy
unsafe blocks Minimize Clippy
Test Coverage
80% cargo-tarpaulin
CI/CD Integration
GitHub Actions
name: Quality on: [push, pull_request]
jobs: quality: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt, clippy
- name: Cache cargo
uses: Swatinem/rust-cache@v2
- name: Check formatting
run: cargo fmt -- --check
- name: Clippy
run: cargo clippy --all-targets --all-features -- -D warnings
- name: Run tests
run: cargo test --all-features
- name: Build docs
run: cargo doc --no-deps
env:
RUSTDOCFLAGS: -D warnings
Anti-Patterns
Anti-Pattern Why It's Bad Correct Approach
unwrap() in library code Panics propagate Use ? operator
Excessive clone()
Performance cost Borrow when possible
#[allow(clippy::all)]
Hides all issues Allow specific lints
unsafe without comment Unclear safety Document invariants
String for everything No type safety Use enums/newtypes
Giant functions Hard to test/maintain Extract smaller functions
Quick Troubleshooting
Issue Likely Cause Solution
Clippy false positive Edge case or intended #[allow(clippy::lint)] with comment
rustfmt changes code Formatting opinion Configure rustfmt.toml
Lint conflicts Pedantic vs nursery Prioritize in Cargo.toml
Slow compilation Many dependencies Use cargo-chef for caching
Dead code warnings Unused exports Add #[cfg(test)] or remove
Related Skills
-
SonarQube
-
Clean Code
-
Rust Security