mirror of
https://github.com/affaan-m/everything-claude-code.git
synced 2026-03-30 21:53:28 +08:00
* feat(rules): add Rust coding style, hooks, and patterns rules Add language-specific rules for Rust extending the common rule set: - coding-style.md: rustfmt, clippy, ownership idioms, error handling, iterator patterns, module organization, visibility - hooks.md: PostToolUse hooks for rustfmt, clippy, cargo check - patterns.md: trait-based repository, newtype, enum state machines, builder, sealed traits, API response envelope Rules reference existing rust-patterns skill for deep content. Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering> * feat(rules): add Rust testing and security rules Add remaining Rust language-specific rules: - testing.md: cargo test, rstest parameterized tests, mockall mocking with mock! macro, tokio async tests, cargo-llvm-cov coverage - security.md: secrets via env vars, parameterized SQL with sqlx, parse-don't-validate input validation, unsafe code audit requirements, cargo-audit dependency scanning, proper HTTP error status codes Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering> * fix(rules): address review feedback on Rust rules Fixes from Copilot, Greptile, Cubic, and CodeRabbit reviews: - Add missing imports: use std::borrow::Cow, use anyhow::Context - Use anyhow::Result<T> consistently (patterns.md, security.md) - Change sqlx placeholder from ? to $1 (Postgres is most common) - Remove Cargo.lock from hooks.md paths (auto-generated file) - Fix tokio::test to show attribute form #[tokio::test] - Fix mockall mock! name collision, wrap in #[cfg(test)] mod tests - Fix --test target to match file layout (api_test, not integration) Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering> * fix: update catalog counts in README.md and AGENTS.md Update documented counts to match actual repository state after rebase: - Skills: 109 → 113 (new skills merged to main) - Commands: 57 → 58 (new command merged to main) Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering> --------- Co-authored-by: Chris Yau <chris@diveanddev.com> Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Happy <yesreply@happy.engineering>
4.1 KiB
4.1 KiB
paths
| paths | |
|---|---|
|
Rust Coding Style
This file extends common/coding-style.md with Rust-specific content.
Formatting
- rustfmt for enforcement — always run
cargo fmtbefore committing - clippy for lints —
cargo clippy -- -D warnings(treat warnings as errors) - 4-space indent (rustfmt default)
- Max line width: 100 characters (rustfmt default)
Immutability
Rust variables are immutable by default — embrace this:
- Use
letby default; only uselet mutwhen mutation is required - Prefer returning new values over mutating in place
- Use
Cow<'_, T>when a function may or may not need to allocate
use std::borrow::Cow;
// GOOD — immutable by default, new value returned
fn normalize(input: &str) -> Cow<'_, str> {
if input.contains(' ') {
Cow::Owned(input.replace(' ', "_"))
} else {
Cow::Borrowed(input)
}
}
// BAD — unnecessary mutation
fn normalize_bad(input: &mut String) {
*input = input.replace(' ', "_");
}
Naming
Follow standard Rust conventions:
snake_casefor functions, methods, variables, modules, cratesPascalCase(UpperCamelCase) for types, traits, enums, type parametersSCREAMING_SNAKE_CASEfor constants and statics- Lifetimes: short lowercase (
'a,'de) — descriptive names for complex cases ('input)
Ownership and Borrowing
- Borrow (
&T) by default; take ownership only when you need to store or consume - Never clone to satisfy the borrow checker without understanding the root cause
- Accept
&stroverString,&[T]overVec<T>in function parameters - Use
impl Into<String>for constructors that need to own aString
// GOOD — borrows when ownership isn't needed
fn word_count(text: &str) -> usize {
text.split_whitespace().count()
}
// GOOD — takes ownership in constructor via Into
fn new(name: impl Into<String>) -> Self {
Self { name: name.into() }
}
// BAD — takes String when &str suffices
fn word_count_bad(text: String) -> usize {
text.split_whitespace().count()
}
Error Handling
- Use
Result<T, E>and?for propagation — neverunwrap()in production code - Libraries: define typed errors with
thiserror - Applications: use
anyhowfor flexible error context - Add context with
.with_context(|| format!("failed to ..."))? - Reserve
unwrap()/expect()for tests and truly unreachable states
// GOOD — library error with thiserror
#[derive(Debug, thiserror::Error)]
pub enum ConfigError {
#[error("failed to read config: {0}")]
Io(#[from] std::io::Error),
#[error("invalid config format: {0}")]
Parse(String),
}
// GOOD — application error with anyhow
use anyhow::Context;
fn load_config(path: &str) -> anyhow::Result<Config> {
let content = std::fs::read_to_string(path)
.with_context(|| format!("failed to read {path}"))?;
toml::from_str(&content)
.with_context(|| format!("failed to parse {path}"))
}
Iterators Over Loops
Prefer iterator chains for transformations; use loops for complex control flow:
// GOOD — declarative and composable
let active_emails: Vec<&str> = users.iter()
.filter(|u| u.is_active)
.map(|u| u.email.as_str())
.collect();
// GOOD — loop for complex logic with early returns
for user in &users {
if let Some(verified) = verify_email(&user.email)? {
send_welcome(&verified)?;
}
}
Module Organization
Organize by domain, not by type:
src/
├── main.rs
├── lib.rs
├── auth/ # Domain module
│ ├── mod.rs
│ ├── token.rs
│ └── middleware.rs
├── orders/ # Domain module
│ ├── mod.rs
│ ├── model.rs
│ └── service.rs
└── db/ # Infrastructure
├── mod.rs
└── pool.rs
Visibility
- Default to private; use
pub(crate)for internal sharing - Only mark
pubwhat is part of the crate's public API - Re-export public API from
lib.rs
References
See skill: rust-patterns for comprehensive Rust idioms and patterns.