agy-superpowers 5.1.4 → 5.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/template/agent/skills/rust-developer/SKILL.md +281 -0
- package/template/agent/skills/rust-developer/references/rust-rules/_sections.md +231 -0
- package/template/agent/skills/rust-developer/references/rust-rules/anti-clone-excessive.md +124 -0
- package/template/agent/skills/rust-developer/references/rust-rules/anti-collect-intermediate.md +131 -0
- package/template/agent/skills/rust-developer/references/rust-rules/anti-empty-catch.md +132 -0
- package/template/agent/skills/rust-developer/references/rust-rules/anti-expect-lazy.md +95 -0
- package/template/agent/skills/rust-developer/references/rust-rules/anti-format-hot-path.md +141 -0
- package/template/agent/skills/rust-developer/references/rust-rules/anti-index-over-iter.md +125 -0
- package/template/agent/skills/rust-developer/references/rust-rules/anti-lock-across-await.md +127 -0
- package/template/agent/skills/rust-developer/references/rust-rules/anti-over-abstraction.md +120 -0
- package/template/agent/skills/rust-developer/references/rust-rules/anti-panic-expected.md +131 -0
- package/template/agent/skills/rust-developer/references/rust-rules/anti-premature-optimize.md +156 -0
- package/template/agent/skills/rust-developer/references/rust-rules/anti-string-for-str.md +122 -0
- package/template/agent/skills/rust-developer/references/rust-rules/anti-stringly-typed.md +167 -0
- package/template/agent/skills/rust-developer/references/rust-rules/anti-type-erasure.md +134 -0
- package/template/agent/skills/rust-developer/references/rust-rules/anti-unwrap-abuse.md +143 -0
- package/template/agent/skills/rust-developer/references/rust-rules/anti-vec-for-slice.md +121 -0
- package/template/agent/skills/rust-developer/references/rust-rules/api-builder-must-use.md +143 -0
- package/template/agent/skills/rust-developer/references/rust-rules/api-builder-pattern.md +187 -0
- package/template/agent/skills/rust-developer/references/rust-rules/api-common-traits.md +165 -0
- package/template/agent/skills/rust-developer/references/rust-rules/api-default-impl.md +177 -0
- package/template/agent/skills/rust-developer/references/rust-rules/api-extension-trait.md +163 -0
- package/template/agent/skills/rust-developer/references/rust-rules/api-from-not-into.md +146 -0
- package/template/agent/skills/rust-developer/references/rust-rules/api-impl-asref.md +142 -0
- package/template/agent/skills/rust-developer/references/rust-rules/api-impl-into.md +160 -0
- package/template/agent/skills/rust-developer/references/rust-rules/api-must-use.md +125 -0
- package/template/agent/skills/rust-developer/references/rust-rules/api-newtype-safety.md +162 -0
- package/template/agent/skills/rust-developer/references/rust-rules/api-non-exhaustive.md +177 -0
- package/template/agent/skills/rust-developer/references/rust-rules/api-parse-dont-validate.md +184 -0
- package/template/agent/skills/rust-developer/references/rust-rules/api-sealed-trait.md +168 -0
- package/template/agent/skills/rust-developer/references/rust-rules/api-serde-optional.md +182 -0
- package/template/agent/skills/rust-developer/references/rust-rules/api-typestate.md +199 -0
- package/template/agent/skills/rust-developer/references/rust-rules/async-bounded-channel.md +175 -0
- package/template/agent/skills/rust-developer/references/rust-rules/async-broadcast-pubsub.md +185 -0
- package/template/agent/skills/rust-developer/references/rust-rules/async-cancellation-token.md +203 -0
- package/template/agent/skills/rust-developer/references/rust-rules/async-clone-before-await.md +171 -0
- package/template/agent/skills/rust-developer/references/rust-rules/async-join-parallel.md +158 -0
- package/template/agent/skills/rust-developer/references/rust-rules/async-joinset-structured.md +195 -0
- package/template/agent/skills/rust-developer/references/rust-rules/async-mpsc-queue.md +171 -0
- package/template/agent/skills/rust-developer/references/rust-rules/async-no-lock-await.md +156 -0
- package/template/agent/skills/rust-developer/references/rust-rules/async-oneshot-response.md +191 -0
- package/template/agent/skills/rust-developer/references/rust-rules/async-select-racing.md +198 -0
- package/template/agent/skills/rust-developer/references/rust-rules/async-spawn-blocking.md +154 -0
- package/template/agent/skills/rust-developer/references/rust-rules/async-tokio-fs.md +167 -0
- package/template/agent/skills/rust-developer/references/rust-rules/async-tokio-runtime.md +169 -0
- package/template/agent/skills/rust-developer/references/rust-rules/async-try-join.md +172 -0
- package/template/agent/skills/rust-developer/references/rust-rules/async-watch-latest.md +189 -0
- package/template/agent/skills/rust-developer/references/rust-rules/doc-all-public.md +113 -0
- package/template/agent/skills/rust-developer/references/rust-rules/doc-cargo-metadata.md +147 -0
- package/template/agent/skills/rust-developer/references/rust-rules/doc-errors-section.md +122 -0
- package/template/agent/skills/rust-developer/references/rust-rules/doc-examples-section.md +161 -0
- package/template/agent/skills/rust-developer/references/rust-rules/doc-hidden-setup.md +149 -0
- package/template/agent/skills/rust-developer/references/rust-rules/doc-intra-links.md +138 -0
- package/template/agent/skills/rust-developer/references/rust-rules/doc-link-types.md +169 -0
- package/template/agent/skills/rust-developer/references/rust-rules/doc-module-inner.md +116 -0
- package/template/agent/skills/rust-developer/references/rust-rules/doc-panics-section.md +128 -0
- package/template/agent/skills/rust-developer/references/rust-rules/doc-question-mark.md +136 -0
- package/template/agent/skills/rust-developer/references/rust-rules/doc-safety-section.md +131 -0
- package/template/agent/skills/rust-developer/references/rust-rules/err-anyhow-app.md +179 -0
- package/template/agent/skills/rust-developer/references/rust-rules/err-context-chain.md +144 -0
- package/template/agent/skills/rust-developer/references/rust-rules/err-custom-type.md +152 -0
- package/template/agent/skills/rust-developer/references/rust-rules/err-doc-errors.md +145 -0
- package/template/agent/skills/rust-developer/references/rust-rules/err-expect-bugs-only.md +133 -0
- package/template/agent/skills/rust-developer/references/rust-rules/err-from-impl.md +152 -0
- package/template/agent/skills/rust-developer/references/rust-rules/err-lowercase-msg.md +124 -0
- package/template/agent/skills/rust-developer/references/rust-rules/err-no-unwrap-prod.md +115 -0
- package/template/agent/skills/rust-developer/references/rust-rules/err-question-mark.md +151 -0
- package/template/agent/skills/rust-developer/references/rust-rules/err-result-over-panic.md +130 -0
- package/template/agent/skills/rust-developer/references/rust-rules/err-source-chain.md +155 -0
- package/template/agent/skills/rust-developer/references/rust-rules/err-thiserror-lib.md +171 -0
- package/template/agent/skills/rust-developer/references/rust-rules/lint-cargo-metadata.md +138 -0
- package/template/agent/skills/rust-developer/references/rust-rules/lint-deny-correctness.md +107 -0
- package/template/agent/skills/rust-developer/references/rust-rules/lint-missing-docs.md +154 -0
- package/template/agent/skills/rust-developer/references/rust-rules/lint-pedantic-selective.md +118 -0
- package/template/agent/skills/rust-developer/references/rust-rules/lint-rustfmt-check.md +157 -0
- package/template/agent/skills/rust-developer/references/rust-rules/lint-unsafe-doc.md +133 -0
- package/template/agent/skills/rust-developer/references/rust-rules/lint-warn-complexity.md +131 -0
- package/template/agent/skills/rust-developer/references/rust-rules/lint-warn-perf.md +136 -0
- package/template/agent/skills/rust-developer/references/rust-rules/lint-warn-style.md +135 -0
- package/template/agent/skills/rust-developer/references/rust-rules/lint-warn-suspicious.md +122 -0
- package/template/agent/skills/rust-developer/references/rust-rules/lint-workspace-lints.md +172 -0
- package/template/agent/skills/rust-developer/references/rust-rules/mem-arena-allocator.md +168 -0
- package/template/agent/skills/rust-developer/references/rust-rules/mem-arrayvec.md +142 -0
- package/template/agent/skills/rust-developer/references/rust-rules/mem-assert-type-size.md +168 -0
- package/template/agent/skills/rust-developer/references/rust-rules/mem-avoid-format.md +147 -0
- package/template/agent/skills/rust-developer/references/rust-rules/mem-box-large-variant.md +158 -0
- package/template/agent/skills/rust-developer/references/rust-rules/mem-boxed-slice.md +139 -0
- package/template/agent/skills/rust-developer/references/rust-rules/mem-clone-from.md +147 -0
- package/template/agent/skills/rust-developer/references/rust-rules/mem-compact-string.md +149 -0
- package/template/agent/skills/rust-developer/references/rust-rules/mem-reuse-collections.md +174 -0
- package/template/agent/skills/rust-developer/references/rust-rules/mem-smaller-integers.md +159 -0
- package/template/agent/skills/rust-developer/references/rust-rules/mem-smallvec.md +138 -0
- package/template/agent/skills/rust-developer/references/rust-rules/mem-thinvec.md +142 -0
- package/template/agent/skills/rust-developer/references/rust-rules/mem-with-capacity.md +156 -0
- package/template/agent/skills/rust-developer/references/rust-rules/mem-write-over-format.md +172 -0
- package/template/agent/skills/rust-developer/references/rust-rules/mem-zero-copy.md +164 -0
- package/template/agent/skills/rust-developer/references/rust-rules/name-acronym-word.md +99 -0
- package/template/agent/skills/rust-developer/references/rust-rules/name-as-free.md +104 -0
- package/template/agent/skills/rust-developer/references/rust-rules/name-consts-screaming.md +94 -0
- package/template/agent/skills/rust-developer/references/rust-rules/name-crate-no-rs.md +78 -0
- package/template/agent/skills/rust-developer/references/rust-rules/name-funcs-snake.md +76 -0
- package/template/agent/skills/rust-developer/references/rust-rules/name-into-ownership.md +123 -0
- package/template/agent/skills/rust-developer/references/rust-rules/name-is-has-bool.md +127 -0
- package/template/agent/skills/rust-developer/references/rust-rules/name-iter-convention.md +129 -0
- package/template/agent/skills/rust-developer/references/rust-rules/name-iter-method.md +131 -0
- package/template/agent/skills/rust-developer/references/rust-rules/name-iter-type-match.md +142 -0
- package/template/agent/skills/rust-developer/references/rust-rules/name-lifetime-short.md +86 -0
- package/template/agent/skills/rust-developer/references/rust-rules/name-no-get-prefix.md +154 -0
- package/template/agent/skills/rust-developer/references/rust-rules/name-to-expensive.md +118 -0
- package/template/agent/skills/rust-developer/references/rust-rules/name-type-param-single.md +92 -0
- package/template/agent/skills/rust-developer/references/rust-rules/name-types-camel.md +65 -0
- package/template/agent/skills/rust-developer/references/rust-rules/name-variants-camel.md +101 -0
- package/template/agent/skills/rust-developer/references/rust-rules/opt-bounds-check.md +161 -0
- package/template/agent/skills/rust-developer/references/rust-rules/opt-cache-friendly.md +187 -0
- package/template/agent/skills/rust-developer/references/rust-rules/opt-codegen-units.md +142 -0
- package/template/agent/skills/rust-developer/references/rust-rules/opt-cold-unlikely.md +152 -0
- package/template/agent/skills/rust-developer/references/rust-rules/opt-inline-always-rare.md +141 -0
- package/template/agent/skills/rust-developer/references/rust-rules/opt-inline-never-cold.md +181 -0
- package/template/agent/skills/rust-developer/references/rust-rules/opt-inline-small.md +160 -0
- package/template/agent/skills/rust-developer/references/rust-rules/opt-likely-hint.md +171 -0
- package/template/agent/skills/rust-developer/references/rust-rules/opt-lto-release.md +130 -0
- package/template/agent/skills/rust-developer/references/rust-rules/opt-pgo-profile.md +167 -0
- package/template/agent/skills/rust-developer/references/rust-rules/opt-simd-portable.md +144 -0
- package/template/agent/skills/rust-developer/references/rust-rules/opt-target-cpu.md +154 -0
- package/template/agent/skills/rust-developer/references/rust-rules/own-arc-shared.md +141 -0
- package/template/agent/skills/rust-developer/references/rust-rules/own-borrow-over-clone.md +95 -0
- package/template/agent/skills/rust-developer/references/rust-rules/own-clone-explicit.md +135 -0
- package/template/agent/skills/rust-developer/references/rust-rules/own-copy-small.md +124 -0
- package/template/agent/skills/rust-developer/references/rust-rules/own-cow-conditional.md +135 -0
- package/template/agent/skills/rust-developer/references/rust-rules/own-lifetime-elision.md +134 -0
- package/template/agent/skills/rust-developer/references/rust-rules/own-move-large.md +134 -0
- package/template/agent/skills/rust-developer/references/rust-rules/own-mutex-interior.md +105 -0
- package/template/agent/skills/rust-developer/references/rust-rules/own-rc-single-thread.md +65 -0
- package/template/agent/skills/rust-developer/references/rust-rules/own-refcell-interior.md +97 -0
- package/template/agent/skills/rust-developer/references/rust-rules/own-rwlock-readers.md +122 -0
- package/template/agent/skills/rust-developer/references/rust-rules/own-slice-over-vec.md +119 -0
- package/template/agent/skills/rust-developer/references/rust-rules/perf-black-box-bench.md +153 -0
- package/template/agent/skills/rust-developer/references/rust-rules/perf-chain-avoid.md +136 -0
- package/template/agent/skills/rust-developer/references/rust-rules/perf-collect-into.md +133 -0
- package/template/agent/skills/rust-developer/references/rust-rules/perf-collect-once.md +120 -0
- package/template/agent/skills/rust-developer/references/rust-rules/perf-drain-reuse.md +137 -0
- package/template/agent/skills/rust-developer/references/rust-rules/perf-entry-api.md +134 -0
- package/template/agent/skills/rust-developer/references/rust-rules/perf-extend-batch.md +150 -0
- package/template/agent/skills/rust-developer/references/rust-rules/perf-iter-lazy.md +123 -0
- package/template/agent/skills/rust-developer/references/rust-rules/perf-iter-over-index.md +113 -0
- package/template/agent/skills/rust-developer/references/rust-rules/perf-profile-first.md +175 -0
- package/template/agent/skills/rust-developer/references/rust-rules/perf-release-profile.md +149 -0
- package/template/agent/skills/rust-developer/references/rust-rules/proj-bin-dir.md +142 -0
- package/template/agent/skills/rust-developer/references/rust-rules/proj-flat-small.md +133 -0
- package/template/agent/skills/rust-developer/references/rust-rules/proj-lib-main-split.md +148 -0
- package/template/agent/skills/rust-developer/references/rust-rules/proj-mod-by-feature.md +130 -0
- package/template/agent/skills/rust-developer/references/rust-rules/proj-mod-rs-dir.md +120 -0
- package/template/agent/skills/rust-developer/references/rust-rules/proj-prelude-module.md +155 -0
- package/template/agent/skills/rust-developer/references/rust-rules/proj-pub-crate-internal.md +139 -0
- package/template/agent/skills/rust-developer/references/rust-rules/proj-pub-super-parent.md +135 -0
- package/template/agent/skills/rust-developer/references/rust-rules/proj-pub-use-reexport.md +162 -0
- package/template/agent/skills/rust-developer/references/rust-rules/proj-workspace-deps.md +186 -0
- package/template/agent/skills/rust-developer/references/rust-rules/proj-workspace-large.md +162 -0
- package/template/agent/skills/rust-developer/references/rust-rules/test-arrange-act-assert.md +160 -0
- package/template/agent/skills/rust-developer/references/rust-rules/test-cfg-test-module.md +151 -0
- package/template/agent/skills/rust-developer/references/rust-rules/test-criterion-bench.md +171 -0
- package/template/agent/skills/rust-developer/references/rust-rules/test-descriptive-names.md +142 -0
- package/template/agent/skills/rust-developer/references/rust-rules/test-doctest-examples.md +168 -0
- package/template/agent/skills/rust-developer/references/rust-rules/test-fixture-raii.md +151 -0
- package/template/agent/skills/rust-developer/references/rust-rules/test-integration-dir.md +144 -0
- package/template/agent/skills/rust-developer/references/rust-rules/test-mock-traits.md +189 -0
- package/template/agent/skills/rust-developer/references/rust-rules/test-mockall-mocking.md +226 -0
- package/template/agent/skills/rust-developer/references/rust-rules/test-proptest-properties.md +161 -0
- package/template/agent/skills/rust-developer/references/rust-rules/test-should-panic.md +130 -0
- package/template/agent/skills/rust-developer/references/rust-rules/test-tokio-async.md +154 -0
- package/template/agent/skills/rust-developer/references/rust-rules/test-use-super.md +127 -0
- package/template/agent/skills/rust-developer/references/rust-rules/type-enum-states.md +154 -0
- package/template/agent/skills/rust-developer/references/rust-rules/type-generic-bounds.md +142 -0
- package/template/agent/skills/rust-developer/references/rust-rules/type-never-diverge.md +146 -0
- package/template/agent/skills/rust-developer/references/rust-rules/type-newtype-ids.md +160 -0
- package/template/agent/skills/rust-developer/references/rust-rules/type-newtype-validated.md +159 -0
- package/template/agent/skills/rust-developer/references/rust-rules/type-no-stringly.md +144 -0
- package/template/agent/skills/rust-developer/references/rust-rules/type-option-nullable.md +137 -0
- package/template/agent/skills/rust-developer/references/rust-rules/type-phantom-marker.md +188 -0
- package/template/agent/skills/rust-developer/references/rust-rules/type-repr-transparent.md +143 -0
- package/template/agent/skills/rust-developer/references/rust-rules/type-result-fallible.md +131 -0
package/package.json
CHANGED
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: rust-developer
|
|
3
|
+
description: Use when writing Rust code, reviewing Rust, debugging ownership/borrow errors, designing APIs in Rust, or choosing async patterns, memory strategies, and idiomatic Rust conventions
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Rust Developer Lens
|
|
7
|
+
|
|
8
|
+
> **Philosophy:** Make invalid states unrepresentable. Let the compiler prove correctness.
|
|
9
|
+
> If it compiles without `unsafe`, `unwrap`, or `clone` sprawl, it's probably right.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## ⚠️ ASK BEFORE ASSUMING
|
|
14
|
+
|
|
15
|
+
If the context is unspecified, ask:
|
|
16
|
+
|
|
17
|
+
| What | Why it matters |
|
|
18
|
+
|------|----------------|
|
|
19
|
+
| **Async runtime?** Tokio / async-std / none | Shapes the entire async stack |
|
|
20
|
+
| **Library or application?** | Changes error handling strategy (`thiserror` vs `anyhow`) |
|
|
21
|
+
| **Target?** WASM / embedded / server / CLI | Changes allowed dependencies and allocation model |
|
|
22
|
+
| **Edition?** 2021 / 2018 | Affects imports, closures, `let`-chains |
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Core Instincts
|
|
27
|
+
|
|
28
|
+
- **Borrow, don't clone** — every `.clone()` is a cost; most can be avoided with `&T`
|
|
29
|
+
- **`unwrap()` is a panic bug waiting to happen** — use `?`, `.context()`, or pattern match
|
|
30
|
+
- **Parse, don't validate** — convert untrusted input into a well-typed value at the boundary
|
|
31
|
+
- **Make illegal states unrepresentable** — enums over booleans, newtypes over raw primitives
|
|
32
|
+
- **Async is not free** — wrong executor choices and `Mutex` across `.await` cause silent deadlocks
|
|
33
|
+
- **Run `cargo clippy` and `cargo fmt`** — treat clippy warnings as errors in CI
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## ❌ Anti-Patterns to Avoid
|
|
38
|
+
|
|
39
|
+
| ❌ NEVER DO | Why | ✅ DO INSTEAD |
|
|
40
|
+
|------------|-----|--------------|
|
|
41
|
+
| `.unwrap()` in production | Panics on unexpected input | Use `?` operator with proper error types |
|
|
42
|
+
| `&String` / `&Vec<T>` as params | Unnecessarily restrictive | Accept `&str` / `&[T]` |
|
|
43
|
+
| `.clone()` to satisfy borrow checker | Wasted allocation | Restructure ownership or borrow correctly |
|
|
44
|
+
| `Box<dyn Error>` as return type | Loses type info, hard to match | Use `thiserror` enum or `anyhow::Error` |
|
|
45
|
+
| `std::fs` in async code | Blocks the executor thread | Use `tokio::fs` |
|
|
46
|
+
| Holding `Mutex` across `.await` | Deadlock risk | Release lock before awaiting |
|
|
47
|
+
| Stringly-typed IDs / states | Runtime errors, no compiler help | Newtypes: `UserId(u64)`, enums for state |
|
|
48
|
+
| `format!()` to build strings repeatedly | Unnecessary allocations | Use `write!()` or `String::with_capacity()` |
|
|
49
|
+
| `Vec<T>` when size is fixed | Heap indirection | `Box<[T]>` or `ArrayVec` |
|
|
50
|
+
| Ignoring clippy lint | Dead code, perf issues, bugs | Fix or `#[allow(...)]` with comment |
|
|
51
|
+
| `unsafe` without justification | Undefined behavior, soundness hole | Minimize scope, document invariants, wrap in safe API |
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Ownership Quick Reference
|
|
56
|
+
|
|
57
|
+
| Situation | Pattern |
|
|
58
|
+
|-----------|---------|
|
|
59
|
+
| Shared read-only | `&T` — borrow |
|
|
60
|
+
| Shared multi-thread | `Arc<T>` |
|
|
61
|
+
| Single-thread shared mutable | `Rc<RefCell<T>>` |
|
|
62
|
+
| Multi-thread shared mutable | `Arc<Mutex<T>>` |
|
|
63
|
+
| Read-heavy shared mutable | `Arc<RwLock<T>>` |
|
|
64
|
+
| Conditional ownership | `Cow<'a, T>` |
|
|
65
|
+
| Small, `Copy`able types | Derive `Copy` |
|
|
66
|
+
| Large data transfer | Move, don't clone |
|
|
67
|
+
| Function param (read) | `&str` / `&[T]` / `&T` |
|
|
68
|
+
| Function param (owned) | `impl Into<T>` |
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## Error Handling Strategy
|
|
73
|
+
|
|
74
|
+
```
|
|
75
|
+
Library crate? → thiserror + custom enum
|
|
76
|
+
Application? → anyhow + .context("what failed")
|
|
77
|
+
Both? → thiserror internally, anyhow at main/binary layer
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
**Pattern:**
|
|
81
|
+
```rust
|
|
82
|
+
// Library: typed, matchable errors
|
|
83
|
+
#[derive(Debug, thiserror::Error)]
|
|
84
|
+
pub enum AppError {
|
|
85
|
+
#[error("user {0} not found")]
|
|
86
|
+
NotFound(UserId),
|
|
87
|
+
#[error("database error")]
|
|
88
|
+
Db(#[from] sqlx::Error),
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Application: add context at call site
|
|
92
|
+
let user = db.find_user(id).await.context("loading user for request")?;
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
**Rules:**
|
|
96
|
+
- Error messages: lowercase, no trailing punctuation
|
|
97
|
+
- Use `?` for propagation — not `match Ok/Err`
|
|
98
|
+
- Document errors with `# Errors` section in doc comments
|
|
99
|
+
- `.expect()` only for programming errors (invariants): `vec.first().expect("vec always has one element")`
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## Async Patterns
|
|
104
|
+
|
|
105
|
+
| Pattern | Use when |
|
|
106
|
+
|---------|----------|
|
|
107
|
+
| `tokio::spawn` | Fire-and-forget task |
|
|
108
|
+
| `tokio::join!` | Parallel independent futures |
|
|
109
|
+
| `tokio::try_join!` | Parallel fallible futures |
|
|
110
|
+
| `tokio::select!` | Race / timeout |
|
|
111
|
+
| `JoinSet` | Dynamic set of tasks |
|
|
112
|
+
| `mpsc` channel | Work queue, producer → consumer |
|
|
113
|
+
| `broadcast` channel | Pub/sub, one → many |
|
|
114
|
+
| `watch` channel | Latest value (config, state) |
|
|
115
|
+
| `oneshot` channel | Request/response pattern |
|
|
116
|
+
| `spawn_blocking` | CPU-bound work from async context |
|
|
117
|
+
| `CancellationToken` | Graceful shutdown signal |
|
|
118
|
+
|
|
119
|
+
**Critical rules:**
|
|
120
|
+
- Never hold `Mutex` / `RwLock` guard across `.await`
|
|
121
|
+
- Use `tokio::fs`, not `std::fs` in async code
|
|
122
|
+
- Clone data *before* await points, release locks *before* yield
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## Memory Optimization Quick Reference
|
|
127
|
+
|
|
128
|
+
| Situation | Tool |
|
|
129
|
+
|-----------|------|
|
|
130
|
+
| Know the size upfront | `Vec::with_capacity(n)` |
|
|
131
|
+
| Usually small (≤ ~8 items) | `SmallVec<[T; 8]>` |
|
|
132
|
+
| Bounded max size | `ArrayVec<T, N>` |
|
|
133
|
+
| Often-empty vec | `ThinVec<T>` |
|
|
134
|
+
| Fixed-size, no growth | `Box<[T]>` |
|
|
135
|
+
| Small strings (≤ 24 bytes) | `CompactString` |
|
|
136
|
+
| Reuse allocation in loop | `vec.clear()` (don't drop) |
|
|
137
|
+
| Zero-copy reads | `&[u8]` / `bytes::Bytes` |
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## API Design Rules
|
|
142
|
+
|
|
143
|
+
- **Builder pattern** for structs with ≥ 3 optional fields; add `#[must_use]` to builder type
|
|
144
|
+
- **Newtype** for domain primitives: `struct UserId(u64)`, `struct Email(String)`
|
|
145
|
+
- **Typestate** for compile-time state machines: `Connection<Connected>` vs `Connection<Idle>`
|
|
146
|
+
- **`impl Into<T>`** for string parameters (accepts `&str`, `String`, `Cow<str>`)
|
|
147
|
+
- **`impl AsRef<T>`** for borrowed inputs (accepts `String`, `&str`, `Path`, etc.)
|
|
148
|
+
- **`From<X> for Y`**, not `Into<Y> for X` — `Into` is auto-derived
|
|
149
|
+
- **`#[non_exhaustive]`** on enums / structs you may extend in a minor version
|
|
150
|
+
- **`#[must_use]`** on `Result`-returning functions
|
|
151
|
+
- Gate `serde` behind a feature flag in libraries
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## Naming Conventions
|
|
156
|
+
|
|
157
|
+
| Item | Convention | Example |
|
|
158
|
+
|------|------------|---------|
|
|
159
|
+
| Types, traits, enums | `UpperCamelCase` | `UserService` |
|
|
160
|
+
| Enum variants | `UpperCamelCase` | `NotFound` |
|
|
161
|
+
| Functions, methods, modules | `snake_case` | `find_user` |
|
|
162
|
+
| Constants, statics | `SCREAMING_SNAKE_CASE` | `MAX_RETRIES` |
|
|
163
|
+
| Lifetimes | Short lowercase | `'a`, `'de`, `'src` |
|
|
164
|
+
| Type params | Single uppercase | `T`, `E`, `K`, `V` |
|
|
165
|
+
| Getter (cheap) | No `get_` prefix | `.name()` not `.get_name()` |
|
|
166
|
+
| Boolean methods | `is_`, `has_`, `can_` | `.is_empty()` |
|
|
167
|
+
| Free conversion (ref) | `as_` prefix | `.as_str()` |
|
|
168
|
+
| Expensive conversion | `to_` prefix | `.to_string()` |
|
|
169
|
+
| Ownership transfer | `into_` prefix | `.into_bytes()` |
|
|
170
|
+
| Acronyms | Treat as word | `Uuid`, `HttpClient` |
|
|
171
|
+
| Crate names | No `-rs` suffix | `my-tool` not `my-tool-rs` |
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## Testing Checklist
|
|
176
|
+
|
|
177
|
+
```rust
|
|
178
|
+
// Unit tests: inline, same file
|
|
179
|
+
#[cfg(test)]
|
|
180
|
+
mod tests {
|
|
181
|
+
use super::*;
|
|
182
|
+
|
|
183
|
+
#[test]
|
|
184
|
+
fn test_name_describes_what_and_expected_result() {
|
|
185
|
+
// Arrange
|
|
186
|
+
// Act
|
|
187
|
+
// Assert
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
#[tokio::test]
|
|
191
|
+
async fn async_test_name() { ... }
|
|
192
|
+
}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
- Integration tests → `tests/` directory
|
|
196
|
+
- Property-based testing → `proptest` crate
|
|
197
|
+
- Trait mocking → `mockall` crate
|
|
198
|
+
- Benchmarks → `criterion` crate
|
|
199
|
+
- Doc examples must be runnable (they are tested)
|
|
200
|
+
- RAII pattern for test cleanup (implement `Drop`)
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
## Questions You Always Ask
|
|
205
|
+
|
|
206
|
+
**When writing Rust code:**
|
|
207
|
+
- Is this a library or an application? (determines error handling strategy)
|
|
208
|
+
- Can I borrow instead of clone here?
|
|
209
|
+
- What happens if this `.unwrap()` receives `None` / `Err` in production?
|
|
210
|
+
- Is this `unsafe` block minimized and its invariants documented?
|
|
211
|
+
|
|
212
|
+
**When reviewing Rust code:**
|
|
213
|
+
- Are all `?` propagations wrapped with `.context()`?
|
|
214
|
+
- Would a newtype prevent misuse here (e.g., mixing up `UserId` and `PostId`)?
|
|
215
|
+
- Is this async code holding a lock guard across an `.await`?
|
|
216
|
+
- Does `cargo clippy` pass clean? Any suppressed lints without justification?
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
## Validation Checklist Before Finishing
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
cargo fmt # Format
|
|
224
|
+
cargo clippy # Lint (treat warnings as errors)
|
|
225
|
+
cargo test # All tests pass
|
|
226
|
+
cargo doc --open # Docs render correctly (check `# Errors`, examples)
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
For performance-sensitive code:
|
|
230
|
+
```bash
|
|
231
|
+
cargo bench # via criterion
|
|
232
|
+
RUSTFLAGS="-C target-cpu=native" cargo build --release
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
---
|
|
236
|
+
|
|
237
|
+
## Red Flags in Code Review
|
|
238
|
+
|
|
239
|
+
**Must fix:**
|
|
240
|
+
- [ ] `.unwrap()` or `.expect()` in non-obvious invariant code
|
|
241
|
+
- [ ] `&String` / `&Vec<T>` function parameters
|
|
242
|
+
- [ ] `Box<dyn Error>` as error type in library
|
|
243
|
+
- [ ] `std::fs` used in async function
|
|
244
|
+
- [ ] Mutex/RwLock guard held across `.await`
|
|
245
|
+
- [ ] Clones that could be borrows
|
|
246
|
+
|
|
247
|
+
**Should fix:**
|
|
248
|
+
- [ ] Missing `# Errors` doc section on fallible public functions
|
|
249
|
+
- [ ] No error context added (`?` with no `.context()`)
|
|
250
|
+
- [ ] Missing `with_capacity` when size is known
|
|
251
|
+
- [ ] Stringly-typed IDs or status values
|
|
252
|
+
- [ ] Clippy warnings left unaddressed
|
|
253
|
+
|
|
254
|
+
---
|
|
255
|
+
|
|
256
|
+
## Platform References
|
|
257
|
+
|
|
258
|
+
When this skill is invoked for a Rust project, check `references/rust-rules/`
|
|
259
|
+
for 179 individual rule files from [leonardomso/rust-skills](https://github.com/leonardomso/rust-skills).
|
|
260
|
+
|
|
261
|
+
Each rule covers one specific pattern with:
|
|
262
|
+
- Why it matters
|
|
263
|
+
- Bad code example
|
|
264
|
+
- Good code example
|
|
265
|
+
- Links to official docs
|
|
266
|
+
|
|
267
|
+
Read `references/rust-rules/_sections.md` for the full index organized by
|
|
268
|
+
priority (CRITICAL → REFERENCE). Reference individual rules when working
|
|
269
|
+
on specific areas (ownership, error handling, async, memory, API design, etc.).
|
|
270
|
+
|
|
271
|
+
---
|
|
272
|
+
|
|
273
|
+
## Sources
|
|
274
|
+
|
|
275
|
+
Rules curated from:
|
|
276
|
+
- [Rust API Guidelines](https://rust-lang.github.io/api-guidelines/)
|
|
277
|
+
- [Rust Performance Book](https://nnethercote.github.io/perf-book/)
|
|
278
|
+
- [Rust Design Patterns](https://rust-unofficial.github.io/patterns/)
|
|
279
|
+
- [leonardomso/rust-skills](https://github.com/leonardomso/rust-skills) — 179 rules for AI coding agents
|
|
280
|
+
- [Ranrar/rustic-prompt](https://github.com/Ranrar/rustic-prompt) — multi-agent Rust instruction set
|
|
281
|
+
- Real-world code from: ripgrep, tokio, serde, axum, polars
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
# Rust Rules Index
|
|
2
|
+
|
|
3
|
+
179 rules from [leonardomso/rust-skills](https://github.com/leonardomso/rust-skills), organized by priority.
|
|
4
|
+
|
|
5
|
+
## Rule Categories by Priority
|
|
6
|
+
|
|
7
|
+
| Priority | Category | Impact | Prefix | Rules |
|
|
8
|
+
|----------|----------|--------|--------|-------|
|
|
9
|
+
| 1 | Ownership & Borrowing | CRITICAL | `own-` | 12 |
|
|
10
|
+
| 2 | Error Handling | CRITICAL | `err-` | 12 |
|
|
11
|
+
| 3 | Memory Optimization | CRITICAL | `mem-` | 15 |
|
|
12
|
+
| 4 | API Design | HIGH | `api-` | 15 |
|
|
13
|
+
| 5 | Async/Await | HIGH | `async-` | 15 |
|
|
14
|
+
| 6 | Compiler Optimization | HIGH | `opt-` | 12 |
|
|
15
|
+
| 7 | Naming Conventions | MEDIUM | `name-` | 16 |
|
|
16
|
+
| 8 | Type Safety | MEDIUM | `type-` | 10 |
|
|
17
|
+
| 9 | Testing | MEDIUM | `test-` | 13 |
|
|
18
|
+
| 10 | Documentation | MEDIUM | `doc-` | 11 |
|
|
19
|
+
| 11 | Performance Patterns | MEDIUM | `perf-` | 11 |
|
|
20
|
+
| 12 | Project Structure | LOW | `proj-` | 11 |
|
|
21
|
+
| 13 | Clippy & Linting | LOW | `lint-` | 11 |
|
|
22
|
+
| 14 | Anti-patterns | REFERENCE | `anti-` | 15 |
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
### 1. Ownership & Borrowing (CRITICAL)
|
|
27
|
+
- `own-borrow-over-clone` - Prefer `&T` borrowing over `.clone()`
|
|
28
|
+
- `own-slice-over-vec` - Accept `&[T]` not `&Vec<T>`, `&str` not `&String`
|
|
29
|
+
- `own-cow-conditional` - Use `Cow<'a, T>` for conditional ownership
|
|
30
|
+
- `own-arc-shared` - Use `Arc<T>` for thread-safe shared ownership
|
|
31
|
+
- `own-rc-single-thread` - Use `Rc<T>` for single-threaded sharing
|
|
32
|
+
- `own-refcell-interior` - Use `RefCell<T>` for interior mutability (single-thread)
|
|
33
|
+
- `own-mutex-interior` - Use `Mutex<T>` for interior mutability (multi-thread)
|
|
34
|
+
- `own-rwlock-readers` - Use `RwLock<T>` when reads dominate writes
|
|
35
|
+
- `own-copy-small` - Derive `Copy` for small, trivial types
|
|
36
|
+
- `own-clone-explicit` - Make `Clone` explicit, avoid implicit copies
|
|
37
|
+
- `own-move-large` - Move large data instead of cloning
|
|
38
|
+
- `own-lifetime-elision` - Rely on lifetime elision when possible
|
|
39
|
+
|
|
40
|
+
### 2. Error Handling (CRITICAL)
|
|
41
|
+
- `err-thiserror-lib` - Use `thiserror` for library error types
|
|
42
|
+
- `err-anyhow-app` - Use `anyhow` for application error handling
|
|
43
|
+
- `err-result-over-panic` - Return `Result`, don't panic on expected errors
|
|
44
|
+
- `err-context-chain` - Add context with `.context()` or `.with_context()`
|
|
45
|
+
- `err-no-unwrap-prod` - Never use `.unwrap()` in production code
|
|
46
|
+
- `err-expect-bugs-only` - Use `.expect()` only for programming errors
|
|
47
|
+
- `err-question-mark` - Use `?` operator for clean propagation
|
|
48
|
+
- `err-from-impl` - Use `#[from]` for automatic error conversion
|
|
49
|
+
- `err-source-chain` - Use `#[source]` to chain underlying errors
|
|
50
|
+
- `err-lowercase-msg` - Error messages: lowercase, no trailing punctuation
|
|
51
|
+
- `err-doc-errors` - Document errors with `# Errors` section
|
|
52
|
+
- `err-custom-type` - Create custom error types, not `Box<dyn Error>`
|
|
53
|
+
|
|
54
|
+
### 3. Memory Optimization (CRITICAL)
|
|
55
|
+
- `mem-with-capacity` - Use `with_capacity()` when size is known
|
|
56
|
+
- `mem-smallvec` - Use `SmallVec` for usually-small collections
|
|
57
|
+
- `mem-arrayvec` - Use `ArrayVec` for bounded-size collections
|
|
58
|
+
- `mem-box-large-variant` - Box large enum variants to reduce type size
|
|
59
|
+
- `mem-boxed-slice` - Use `Box<[T]>` instead of `Vec<T>` when fixed
|
|
60
|
+
- `mem-thinvec` - Use `ThinVec` for often-empty vectors
|
|
61
|
+
- `mem-clone-from` - Use `clone_from()` to reuse allocations
|
|
62
|
+
- `mem-reuse-collections` - Reuse collections with `clear()` in loops
|
|
63
|
+
- `mem-avoid-format` - Avoid `format!()` when string literals work
|
|
64
|
+
- `mem-write-over-format` - Use `write!()` instead of `format!()`
|
|
65
|
+
- `mem-arena-allocator` - Use arena allocators for batch allocations
|
|
66
|
+
- `mem-zero-copy` - Use zero-copy patterns with slices and `Bytes`
|
|
67
|
+
- `mem-compact-string` - Use `CompactString` for small string optimization
|
|
68
|
+
- `mem-smaller-integers` - Use smallest integer type that fits
|
|
69
|
+
- `mem-assert-type-size` - Assert hot type sizes to prevent regressions
|
|
70
|
+
|
|
71
|
+
### 4. API Design (HIGH)
|
|
72
|
+
- `api-builder-pattern` - Use Builder pattern for complex construction
|
|
73
|
+
- `api-builder-must-use` - Add `#[must_use]` to builder types
|
|
74
|
+
- `api-newtype-safety` - Use newtypes for type-safe distinctions
|
|
75
|
+
- `api-typestate` - Use typestate for compile-time state machines
|
|
76
|
+
- `api-sealed-trait` - Seal traits to prevent external implementations
|
|
77
|
+
- `api-extension-trait` - Use extension traits to add methods to foreign types
|
|
78
|
+
- `api-parse-dont-validate` - Parse into validated types at boundaries
|
|
79
|
+
- `api-impl-into` - Accept `impl Into<T>` for flexible string inputs
|
|
80
|
+
- `api-impl-asref` - Accept `impl AsRef<T>` for borrowed inputs
|
|
81
|
+
- `api-must-use` - Add `#[must_use]` to `Result` returning functions
|
|
82
|
+
- `api-non-exhaustive` - Use `#[non_exhaustive]` for future-proof enums/structs
|
|
83
|
+
- `api-from-not-into` - Implement `From`, not `Into` (auto-derived)
|
|
84
|
+
- `api-default-impl` - Implement `Default` for sensible defaults
|
|
85
|
+
- `api-common-traits` - Implement `Debug`, `Clone`, `PartialEq` eagerly
|
|
86
|
+
- `api-serde-optional` - Gate `Serialize`/`Deserialize` behind feature flag
|
|
87
|
+
|
|
88
|
+
### 5. Async/Await (HIGH)
|
|
89
|
+
- `async-tokio-runtime` - Use Tokio for production async runtime
|
|
90
|
+
- `async-no-lock-await` - Never hold `Mutex`/`RwLock` across `.await`
|
|
91
|
+
- `async-spawn-blocking` - Use `spawn_blocking` for CPU-intensive work
|
|
92
|
+
- `async-tokio-fs` - Use `tokio::fs` not `std::fs` in async code
|
|
93
|
+
- `async-cancellation-token` - Use `CancellationToken` for graceful shutdown
|
|
94
|
+
- `async-join-parallel` - Use `tokio::join!` for parallel operations
|
|
95
|
+
- `async-try-join` - Use `tokio::try_join!` for fallible parallel ops
|
|
96
|
+
- `async-select-racing` - Use `tokio::select!` for racing/timeouts
|
|
97
|
+
- `async-bounded-channel` - Use bounded channels for backpressure
|
|
98
|
+
- `async-mpsc-queue` - Use `mpsc` for work queues
|
|
99
|
+
- `async-broadcast-pubsub` - Use `broadcast` for pub/sub patterns
|
|
100
|
+
- `async-watch-latest` - Use `watch` for latest-value sharing
|
|
101
|
+
- `async-oneshot-response` - Use `oneshot` for request/response
|
|
102
|
+
- `async-joinset-structured` - Use `JoinSet` for dynamic task groups
|
|
103
|
+
- `async-clone-before-await` - Clone data before await, release locks
|
|
104
|
+
|
|
105
|
+
### 6. Compiler Optimization (HIGH)
|
|
106
|
+
- `opt-inline-small` - Use `#[inline]` for small hot functions
|
|
107
|
+
- `opt-inline-always-rare` - Use `#[inline(always)]` sparingly
|
|
108
|
+
- `opt-inline-never-cold` - Use `#[inline(never)]` for cold paths
|
|
109
|
+
- `opt-cold-unlikely` - Use `#[cold]` for error/unlikely paths
|
|
110
|
+
- `opt-likely-hint` - Use `likely()`/`unlikely()` for branch hints
|
|
111
|
+
- `opt-lto-release` - Enable LTO in release builds
|
|
112
|
+
- `opt-codegen-units` - Use `codegen-units = 1` for max optimization
|
|
113
|
+
- `opt-pgo-profile` - Use PGO for production builds
|
|
114
|
+
- `opt-target-cpu` - Set `target-cpu=native` for local builds
|
|
115
|
+
- `opt-bounds-check` - Use iterators to avoid bounds checks
|
|
116
|
+
- `opt-simd-portable` - Use portable SIMD for data-parallel ops
|
|
117
|
+
- `opt-cache-friendly` - Design cache-friendly data layouts (SoA)
|
|
118
|
+
|
|
119
|
+
### 7. Naming Conventions (MEDIUM)
|
|
120
|
+
- `name-types-camel` - Use `UpperCamelCase` for types, traits, enums
|
|
121
|
+
- `name-variants-camel` - Use `UpperCamelCase` for enum variants
|
|
122
|
+
- `name-funcs-snake` - Use `snake_case` for functions, methods, modules
|
|
123
|
+
- `name-consts-screaming` - Use `SCREAMING_SNAKE_CASE` for constants/statics
|
|
124
|
+
- `name-lifetime-short` - Use short lowercase lifetimes: `'a`, `'de`, `'src`
|
|
125
|
+
- `name-type-param-single` - Use single uppercase for type params: `T`, `E`, `K`, `V`
|
|
126
|
+
- `name-as-free` - `as_` prefix: free reference conversion
|
|
127
|
+
- `name-to-expensive` - `to_` prefix: expensive conversion
|
|
128
|
+
- `name-into-ownership` - `into_` prefix: ownership transfer
|
|
129
|
+
- `name-no-get-prefix` - No `get_` prefix for simple getters
|
|
130
|
+
- `name-is-has-bool` - Use `is_`, `has_`, `can_` for boolean methods
|
|
131
|
+
- `name-iter-convention` - Use `iter`/`iter_mut`/`into_iter` for iterators
|
|
132
|
+
- `name-iter-method` - Name iterator methods consistently
|
|
133
|
+
- `name-iter-type-match` - Iterator type names match method
|
|
134
|
+
- `name-acronym-word` - Treat acronyms as words: `Uuid` not `UUID`
|
|
135
|
+
- `name-crate-no-rs` - Crate names: no `-rs` suffix
|
|
136
|
+
|
|
137
|
+
### 8. Type Safety (MEDIUM)
|
|
138
|
+
- `type-newtype-ids` - Wrap IDs in newtypes: `UserId(u64)`
|
|
139
|
+
- `type-newtype-validated` - Newtypes for validated data: `Email`, `Url`
|
|
140
|
+
- `type-enum-states` - Use enums for mutually exclusive states
|
|
141
|
+
- `type-option-nullable` - Use `Option<T>` for nullable values
|
|
142
|
+
- `type-result-fallible` - Use `Result<T, E>` for fallible operations
|
|
143
|
+
- `type-phantom-marker` - Use `PhantomData<T>` for type-level markers
|
|
144
|
+
- `type-never-diverge` - Use `!` type for functions that never return
|
|
145
|
+
- `type-generic-bounds` - Add trait bounds only where needed
|
|
146
|
+
- `type-no-stringly` - Avoid stringly-typed APIs, use enums/newtypes
|
|
147
|
+
- `type-repr-transparent` - Use `#[repr(transparent)]` for FFI newtypes
|
|
148
|
+
|
|
149
|
+
### 9. Testing (MEDIUM)
|
|
150
|
+
- `test-cfg-test-module` - Use `#[cfg(test)] mod tests { }`
|
|
151
|
+
- `test-use-super` - Use `use super::*;` in test modules
|
|
152
|
+
- `test-integration-dir` - Put integration tests in `tests/` directory
|
|
153
|
+
- `test-descriptive-names` - Use descriptive test names
|
|
154
|
+
- `test-arrange-act-assert` - Structure tests as arrange/act/assert
|
|
155
|
+
- `test-proptest-properties` - Use `proptest` for property-based testing
|
|
156
|
+
- `test-mockall-mocking` - Use `mockall` for trait mocking
|
|
157
|
+
- `test-mock-traits` - Use traits for dependencies to enable mocking
|
|
158
|
+
- `test-fixture-raii` - Use RAII pattern (Drop) for test cleanup
|
|
159
|
+
- `test-tokio-async` - Use `#[tokio::test]` for async tests
|
|
160
|
+
- `test-should-panic` - Use `#[should_panic]` for panic tests
|
|
161
|
+
- `test-criterion-bench` - Use `criterion` for benchmarking
|
|
162
|
+
- `test-doctest-examples` - Keep doc examples as executable tests
|
|
163
|
+
|
|
164
|
+
### 10. Documentation (MEDIUM)
|
|
165
|
+
- `doc-all-public` - Document all public items with `///`
|
|
166
|
+
- `doc-module-inner` - Use `//!` for module-level documentation
|
|
167
|
+
- `doc-examples-section` - Include `# Examples` with runnable code
|
|
168
|
+
- `doc-errors-section` - Include `# Errors` for fallible functions
|
|
169
|
+
- `doc-panics-section` - Include `# Panics` for panicking functions
|
|
170
|
+
- `doc-safety-section` - Include `# Safety` for unsafe functions
|
|
171
|
+
- `doc-question-mark` - Use `?` in examples, not `.unwrap()`
|
|
172
|
+
- `doc-hidden-setup` - Use `# ` prefix to hide example setup code
|
|
173
|
+
- `doc-intra-links` - Use intra-doc links: `[Vec]`
|
|
174
|
+
- `doc-link-types` - Link related types and functions in docs
|
|
175
|
+
- `doc-cargo-metadata` - Fill `Cargo.toml` metadata
|
|
176
|
+
|
|
177
|
+
### 11. Performance Patterns (MEDIUM)
|
|
178
|
+
- `perf-iter-over-index` - Prefer iterators over manual indexing
|
|
179
|
+
- `perf-iter-lazy` - Keep iterators lazy, collect() only when needed
|
|
180
|
+
- `perf-collect-once` - Don't `collect()` intermediate iterators
|
|
181
|
+
- `perf-entry-api` - Use `entry()` API for map insert-or-update
|
|
182
|
+
- `perf-drain-reuse` - Use `drain()` to reuse allocations
|
|
183
|
+
- `perf-extend-batch` - Use `extend()` for batch insertions
|
|
184
|
+
- `perf-chain-avoid` - Avoid `chain()` in hot loops
|
|
185
|
+
- `perf-collect-into` - Use `collect_into()` for reusing containers
|
|
186
|
+
- `perf-black-box-bench` - Use `black_box()` in benchmarks
|
|
187
|
+
- `perf-release-profile` - Optimize release profile settings
|
|
188
|
+
- `perf-profile-first` - Profile before optimizing
|
|
189
|
+
|
|
190
|
+
### 12. Project Structure (LOW)
|
|
191
|
+
- `proj-lib-main-split` - Keep `main.rs` minimal, logic in `lib.rs`
|
|
192
|
+
- `proj-mod-by-feature` - Organize modules by feature, not type
|
|
193
|
+
- `proj-flat-small` - Keep small projects flat
|
|
194
|
+
- `proj-mod-rs-dir` - Use `mod.rs` for multi-file modules
|
|
195
|
+
- `proj-pub-crate-internal` - Use `pub(crate)` for internal APIs
|
|
196
|
+
- `proj-pub-super-parent` - Use `pub(super)` for parent-only visibility
|
|
197
|
+
- `proj-pub-use-reexport` - Use `pub use` for clean public API
|
|
198
|
+
- `proj-prelude-module` - Create `prelude` module for common imports
|
|
199
|
+
- `proj-bin-dir` - Put multiple binaries in `src/bin/`
|
|
200
|
+
- `proj-workspace-large` - Use workspaces for large projects
|
|
201
|
+
- `proj-workspace-deps` - Use workspace dependency inheritance
|
|
202
|
+
|
|
203
|
+
### 13. Clippy & Linting (LOW)
|
|
204
|
+
- `lint-deny-correctness` - `#![deny(clippy::correctness)]`
|
|
205
|
+
- `lint-warn-suspicious` - `#![warn(clippy::suspicious)]`
|
|
206
|
+
- `lint-warn-style` - `#![warn(clippy::style)]`
|
|
207
|
+
- `lint-warn-complexity` - `#![warn(clippy::complexity)]`
|
|
208
|
+
- `lint-warn-perf` - `#![warn(clippy::perf)]`
|
|
209
|
+
- `lint-pedantic-selective` - Enable `clippy::pedantic` selectively
|
|
210
|
+
- `lint-missing-docs` - `#![warn(missing_docs)]`
|
|
211
|
+
- `lint-unsafe-doc` - `#![warn(clippy::undocumented_unsafe_blocks)]`
|
|
212
|
+
- `lint-cargo-metadata` - `#![warn(clippy::cargo)]` for published crates
|
|
213
|
+
- `lint-rustfmt-check` - Run `cargo fmt --check` in CI
|
|
214
|
+
- `lint-workspace-lints` - Configure lints at workspace level
|
|
215
|
+
|
|
216
|
+
### 14. Anti-patterns (REFERENCE)
|
|
217
|
+
- `anti-unwrap-abuse` - Don't use `.unwrap()` in production code
|
|
218
|
+
- `anti-expect-lazy` - Don't use `.expect()` for recoverable errors
|
|
219
|
+
- `anti-clone-excessive` - Don't clone when borrowing works
|
|
220
|
+
- `anti-lock-across-await` - Don't hold locks across `.await`
|
|
221
|
+
- `anti-string-for-str` - Don't accept `&String` when `&str` works
|
|
222
|
+
- `anti-vec-for-slice` - Don't accept `&Vec<T>` when `&[T]` works
|
|
223
|
+
- `anti-index-over-iter` - Don't use indexing when iterators work
|
|
224
|
+
- `anti-panic-expected` - Don't panic on expected/recoverable errors
|
|
225
|
+
- `anti-empty-catch` - Don't use empty `if let Err(_) = ...` blocks
|
|
226
|
+
- `anti-over-abstraction` - Don't over-abstract with excessive generics
|
|
227
|
+
- `anti-premature-optimize` - Don't optimize before profiling
|
|
228
|
+
- `anti-type-erasure` - Don't use `Box<dyn Trait>` when `impl Trait` works
|
|
229
|
+
- `anti-format-hot-path` - Don't use `format!()` in hot paths
|
|
230
|
+
- `anti-collect-intermediate` - Don't `collect()` intermediate iterators
|
|
231
|
+
- `anti-stringly-typed` - Don't use strings for structured data
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# anti-clone-excessive
|
|
2
|
+
|
|
3
|
+
> Don't clone when borrowing works
|
|
4
|
+
|
|
5
|
+
## Why It Matters
|
|
6
|
+
|
|
7
|
+
`.clone()` allocates memory and copies data. When you only need to read data, borrowing (`&T`) is free. Excessive cloning wastes memory, CPU cycles, and often indicates misunderstanding of ownership.
|
|
8
|
+
|
|
9
|
+
## Bad
|
|
10
|
+
|
|
11
|
+
```rust
|
|
12
|
+
// Cloning to pass to a function that only reads
|
|
13
|
+
fn print_name(name: String) { // Takes ownership
|
|
14
|
+
println!("{}", name);
|
|
15
|
+
}
|
|
16
|
+
let name = "Alice".to_string();
|
|
17
|
+
print_name(name.clone()); // Unnecessary clone
|
|
18
|
+
print_name(name); // Could have just done this
|
|
19
|
+
|
|
20
|
+
// Cloning in a loop
|
|
21
|
+
for item in items.clone() { // Clones entire Vec
|
|
22
|
+
process(&item);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Cloning for comparison
|
|
26
|
+
if input.clone() == expected { // Pointless clone
|
|
27
|
+
// ...
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Cloning struct fields
|
|
31
|
+
fn get_name(&self) -> String {
|
|
32
|
+
self.name.clone() // Caller might not need ownership
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Good
|
|
37
|
+
|
|
38
|
+
```rust
|
|
39
|
+
// Accept reference if only reading
|
|
40
|
+
fn print_name(name: &str) {
|
|
41
|
+
println!("{}", name);
|
|
42
|
+
}
|
|
43
|
+
let name = "Alice".to_string();
|
|
44
|
+
print_name(&name); // Borrow, no clone
|
|
45
|
+
|
|
46
|
+
// Iterate by reference
|
|
47
|
+
for item in &items {
|
|
48
|
+
process(item);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Compare by reference
|
|
52
|
+
if input == expected {
|
|
53
|
+
// ...
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Return reference when possible
|
|
57
|
+
fn get_name(&self) -> &str {
|
|
58
|
+
&self.name
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## When to Clone
|
|
63
|
+
|
|
64
|
+
```rust
|
|
65
|
+
// Need owned data for async move
|
|
66
|
+
let name = name.clone();
|
|
67
|
+
tokio::spawn(async move {
|
|
68
|
+
process(name).await;
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
// Storing in a new struct
|
|
72
|
+
struct Cache {
|
|
73
|
+
data: String,
|
|
74
|
+
}
|
|
75
|
+
impl Cache {
|
|
76
|
+
fn store(&mut self, data: &str) {
|
|
77
|
+
self.data = data.to_string(); // Must own
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Multiple owners (use Arc instead if frequent)
|
|
82
|
+
let shared = data.clone();
|
|
83
|
+
thread::spawn(move || use_data(shared));
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Alternatives to Clone
|
|
87
|
+
|
|
88
|
+
| Instead of | Use |
|
|
89
|
+
|------------|-----|
|
|
90
|
+
| `s.clone()` for reading | `&s` |
|
|
91
|
+
| `vec.clone()` for iteration | `&vec` or `vec.iter()` |
|
|
92
|
+
| `Clone` for shared ownership | `Arc<T>` |
|
|
93
|
+
| Clone in hot loop | Move outside loop |
|
|
94
|
+
| `s.to_string()` from `&str` | Accept `&str` if possible |
|
|
95
|
+
|
|
96
|
+
## Pattern: Clone on Write
|
|
97
|
+
|
|
98
|
+
```rust
|
|
99
|
+
use std::borrow::Cow;
|
|
100
|
+
|
|
101
|
+
fn process(input: Cow<str>) -> Cow<str> {
|
|
102
|
+
if needs_modification(&input) {
|
|
103
|
+
Cow::Owned(modify(&input)) // Clone only if needed
|
|
104
|
+
} else {
|
|
105
|
+
input // No clone
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Detecting Excessive Clones
|
|
111
|
+
|
|
112
|
+
```toml
|
|
113
|
+
# Cargo.toml
|
|
114
|
+
[lints.clippy]
|
|
115
|
+
clone_on_copy = "warn"
|
|
116
|
+
clone_on_ref_ptr = "warn"
|
|
117
|
+
redundant_clone = "warn"
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## See Also
|
|
121
|
+
|
|
122
|
+
- [own-borrow-over-clone](./own-borrow-over-clone.md) - Borrowing patterns
|
|
123
|
+
- [own-cow-conditional](./own-cow-conditional.md) - Clone on write
|
|
124
|
+
- [own-arc-shared](./own-arc-shared.md) - Shared ownership
|