agy-superpowers 5.2.2 → 5.2.3
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/README.md +47 -150
- package/package.json +1 -1
- package/template/agent/rules/scratch-scripts.md +37 -0
- package/template/agent/rules/superpowers.md +4 -51
- package/template/agent/skills/ai-integrated-product/SKILL.md +0 -57
- package/template/agent/skills/analytics-setup/SKILL.md +0 -51
- package/template/agent/skills/api-design/SKILL.md +0 -193
- package/template/agent/skills/app-store-optimizer/SKILL.md +0 -127
- package/template/agent/skills/auth-and-identity/SKILL.md +0 -167
- package/template/agent/skills/backend-developer/SKILL.md +0 -148
- package/template/agent/skills/bootstrapper-finance/SKILL.md +0 -55
- package/template/agent/skills/chrome-extension-developer/SKILL.md +0 -53
- package/template/agent/skills/community-manager/SKILL.md +0 -115
- package/template/agent/skills/content-marketer/SKILL.md +0 -111
- package/template/agent/skills/conversion-optimizer/SKILL.md +0 -142
- package/template/agent/skills/cto-architect/SKILL.md +0 -133
- package/template/agent/skills/customer-success-manager/SKILL.md +0 -126
- package/template/agent/skills/data-analyst/SKILL.md +0 -147
- package/template/agent/skills/devops-engineer/SKILL.md +0 -117
- package/template/agent/skills/email-infrastructure/SKILL.md +0 -164
- package/template/agent/skills/game-design/SKILL.md +0 -194
- package/template/agent/skills/game-developer/SKILL.md +0 -175
- package/template/agent/skills/growth-hacker/SKILL.md +0 -122
- package/template/agent/skills/idea-validator/SKILL.md +0 -55
- package/template/agent/skills/indie-legal/SKILL.md +0 -53
- package/template/agent/skills/influencer-marketer/SKILL.md +0 -141
- package/template/agent/skills/landing-page-builder/SKILL.md +0 -59
- package/template/agent/skills/launch-strategist/SKILL.md +0 -62
- package/template/agent/skills/market-researcher/SKILL.md +0 -53
- package/template/agent/skills/micro-saas-builder/SKILL.md +0 -56
- package/template/agent/skills/monetization-strategist/SKILL.md +0 -119
- package/template/agent/skills/paid-acquisition-specialist/SKILL.md +0 -119
- package/template/agent/skills/pricing-psychologist/SKILL.md +0 -58
- package/template/agent/skills/real-time-features/SKILL.md +0 -194
- package/template/agent/skills/retention-specialist/SKILL.md +0 -123
- package/template/agent/skills/rust-developer/SKILL.md +0 -281
- package/template/agent/skills/rust-developer/references/rust-rules/_sections.md +0 -231
- package/template/agent/skills/rust-developer/references/rust-rules/anti-clone-excessive.md +0 -124
- package/template/agent/skills/rust-developer/references/rust-rules/anti-collect-intermediate.md +0 -131
- package/template/agent/skills/rust-developer/references/rust-rules/anti-empty-catch.md +0 -132
- package/template/agent/skills/rust-developer/references/rust-rules/anti-expect-lazy.md +0 -95
- package/template/agent/skills/rust-developer/references/rust-rules/anti-format-hot-path.md +0 -141
- package/template/agent/skills/rust-developer/references/rust-rules/anti-index-over-iter.md +0 -125
- package/template/agent/skills/rust-developer/references/rust-rules/anti-lock-across-await.md +0 -127
- package/template/agent/skills/rust-developer/references/rust-rules/anti-over-abstraction.md +0 -120
- package/template/agent/skills/rust-developer/references/rust-rules/anti-panic-expected.md +0 -131
- package/template/agent/skills/rust-developer/references/rust-rules/anti-premature-optimize.md +0 -156
- package/template/agent/skills/rust-developer/references/rust-rules/anti-string-for-str.md +0 -122
- package/template/agent/skills/rust-developer/references/rust-rules/anti-stringly-typed.md +0 -167
- package/template/agent/skills/rust-developer/references/rust-rules/anti-type-erasure.md +0 -134
- package/template/agent/skills/rust-developer/references/rust-rules/anti-unwrap-abuse.md +0 -143
- package/template/agent/skills/rust-developer/references/rust-rules/anti-vec-for-slice.md +0 -121
- package/template/agent/skills/rust-developer/references/rust-rules/api-builder-must-use.md +0 -143
- package/template/agent/skills/rust-developer/references/rust-rules/api-builder-pattern.md +0 -187
- package/template/agent/skills/rust-developer/references/rust-rules/api-common-traits.md +0 -165
- package/template/agent/skills/rust-developer/references/rust-rules/api-default-impl.md +0 -177
- package/template/agent/skills/rust-developer/references/rust-rules/api-extension-trait.md +0 -163
- package/template/agent/skills/rust-developer/references/rust-rules/api-from-not-into.md +0 -146
- package/template/agent/skills/rust-developer/references/rust-rules/api-impl-asref.md +0 -142
- package/template/agent/skills/rust-developer/references/rust-rules/api-impl-into.md +0 -160
- package/template/agent/skills/rust-developer/references/rust-rules/api-must-use.md +0 -125
- package/template/agent/skills/rust-developer/references/rust-rules/api-newtype-safety.md +0 -162
- package/template/agent/skills/rust-developer/references/rust-rules/api-non-exhaustive.md +0 -177
- package/template/agent/skills/rust-developer/references/rust-rules/api-parse-dont-validate.md +0 -184
- package/template/agent/skills/rust-developer/references/rust-rules/api-sealed-trait.md +0 -168
- package/template/agent/skills/rust-developer/references/rust-rules/api-serde-optional.md +0 -182
- package/template/agent/skills/rust-developer/references/rust-rules/api-typestate.md +0 -199
- package/template/agent/skills/rust-developer/references/rust-rules/async-bounded-channel.md +0 -175
- package/template/agent/skills/rust-developer/references/rust-rules/async-broadcast-pubsub.md +0 -185
- package/template/agent/skills/rust-developer/references/rust-rules/async-cancellation-token.md +0 -203
- package/template/agent/skills/rust-developer/references/rust-rules/async-clone-before-await.md +0 -171
- package/template/agent/skills/rust-developer/references/rust-rules/async-join-parallel.md +0 -158
- package/template/agent/skills/rust-developer/references/rust-rules/async-joinset-structured.md +0 -195
- package/template/agent/skills/rust-developer/references/rust-rules/async-mpsc-queue.md +0 -171
- package/template/agent/skills/rust-developer/references/rust-rules/async-no-lock-await.md +0 -156
- package/template/agent/skills/rust-developer/references/rust-rules/async-oneshot-response.md +0 -191
- package/template/agent/skills/rust-developer/references/rust-rules/async-select-racing.md +0 -198
- package/template/agent/skills/rust-developer/references/rust-rules/async-spawn-blocking.md +0 -154
- package/template/agent/skills/rust-developer/references/rust-rules/async-tokio-fs.md +0 -167
- package/template/agent/skills/rust-developer/references/rust-rules/async-tokio-runtime.md +0 -169
- package/template/agent/skills/rust-developer/references/rust-rules/async-try-join.md +0 -172
- package/template/agent/skills/rust-developer/references/rust-rules/async-watch-latest.md +0 -189
- package/template/agent/skills/rust-developer/references/rust-rules/doc-all-public.md +0 -113
- package/template/agent/skills/rust-developer/references/rust-rules/doc-cargo-metadata.md +0 -147
- package/template/agent/skills/rust-developer/references/rust-rules/doc-errors-section.md +0 -122
- package/template/agent/skills/rust-developer/references/rust-rules/doc-examples-section.md +0 -161
- package/template/agent/skills/rust-developer/references/rust-rules/doc-hidden-setup.md +0 -149
- package/template/agent/skills/rust-developer/references/rust-rules/doc-intra-links.md +0 -138
- package/template/agent/skills/rust-developer/references/rust-rules/doc-link-types.md +0 -169
- package/template/agent/skills/rust-developer/references/rust-rules/doc-module-inner.md +0 -116
- package/template/agent/skills/rust-developer/references/rust-rules/doc-panics-section.md +0 -128
- package/template/agent/skills/rust-developer/references/rust-rules/doc-question-mark.md +0 -136
- package/template/agent/skills/rust-developer/references/rust-rules/doc-safety-section.md +0 -131
- package/template/agent/skills/rust-developer/references/rust-rules/err-anyhow-app.md +0 -179
- package/template/agent/skills/rust-developer/references/rust-rules/err-context-chain.md +0 -144
- package/template/agent/skills/rust-developer/references/rust-rules/err-custom-type.md +0 -152
- package/template/agent/skills/rust-developer/references/rust-rules/err-doc-errors.md +0 -145
- package/template/agent/skills/rust-developer/references/rust-rules/err-expect-bugs-only.md +0 -133
- package/template/agent/skills/rust-developer/references/rust-rules/err-from-impl.md +0 -152
- package/template/agent/skills/rust-developer/references/rust-rules/err-lowercase-msg.md +0 -124
- package/template/agent/skills/rust-developer/references/rust-rules/err-no-unwrap-prod.md +0 -115
- package/template/agent/skills/rust-developer/references/rust-rules/err-question-mark.md +0 -151
- package/template/agent/skills/rust-developer/references/rust-rules/err-result-over-panic.md +0 -130
- package/template/agent/skills/rust-developer/references/rust-rules/err-source-chain.md +0 -155
- package/template/agent/skills/rust-developer/references/rust-rules/err-thiserror-lib.md +0 -171
- package/template/agent/skills/rust-developer/references/rust-rules/lint-cargo-metadata.md +0 -138
- package/template/agent/skills/rust-developer/references/rust-rules/lint-deny-correctness.md +0 -107
- package/template/agent/skills/rust-developer/references/rust-rules/lint-missing-docs.md +0 -154
- package/template/agent/skills/rust-developer/references/rust-rules/lint-pedantic-selective.md +0 -118
- package/template/agent/skills/rust-developer/references/rust-rules/lint-rustfmt-check.md +0 -157
- package/template/agent/skills/rust-developer/references/rust-rules/lint-unsafe-doc.md +0 -133
- package/template/agent/skills/rust-developer/references/rust-rules/lint-warn-complexity.md +0 -131
- package/template/agent/skills/rust-developer/references/rust-rules/lint-warn-perf.md +0 -136
- package/template/agent/skills/rust-developer/references/rust-rules/lint-warn-style.md +0 -135
- package/template/agent/skills/rust-developer/references/rust-rules/lint-warn-suspicious.md +0 -122
- package/template/agent/skills/rust-developer/references/rust-rules/lint-workspace-lints.md +0 -172
- package/template/agent/skills/rust-developer/references/rust-rules/mem-arena-allocator.md +0 -168
- package/template/agent/skills/rust-developer/references/rust-rules/mem-arrayvec.md +0 -142
- package/template/agent/skills/rust-developer/references/rust-rules/mem-assert-type-size.md +0 -168
- package/template/agent/skills/rust-developer/references/rust-rules/mem-avoid-format.md +0 -147
- package/template/agent/skills/rust-developer/references/rust-rules/mem-box-large-variant.md +0 -158
- package/template/agent/skills/rust-developer/references/rust-rules/mem-boxed-slice.md +0 -139
- package/template/agent/skills/rust-developer/references/rust-rules/mem-clone-from.md +0 -147
- package/template/agent/skills/rust-developer/references/rust-rules/mem-compact-string.md +0 -149
- package/template/agent/skills/rust-developer/references/rust-rules/mem-reuse-collections.md +0 -174
- package/template/agent/skills/rust-developer/references/rust-rules/mem-smaller-integers.md +0 -159
- package/template/agent/skills/rust-developer/references/rust-rules/mem-smallvec.md +0 -138
- package/template/agent/skills/rust-developer/references/rust-rules/mem-thinvec.md +0 -142
- package/template/agent/skills/rust-developer/references/rust-rules/mem-with-capacity.md +0 -156
- package/template/agent/skills/rust-developer/references/rust-rules/mem-write-over-format.md +0 -172
- package/template/agent/skills/rust-developer/references/rust-rules/mem-zero-copy.md +0 -164
- package/template/agent/skills/rust-developer/references/rust-rules/name-acronym-word.md +0 -99
- package/template/agent/skills/rust-developer/references/rust-rules/name-as-free.md +0 -104
- package/template/agent/skills/rust-developer/references/rust-rules/name-consts-screaming.md +0 -94
- package/template/agent/skills/rust-developer/references/rust-rules/name-crate-no-rs.md +0 -78
- package/template/agent/skills/rust-developer/references/rust-rules/name-funcs-snake.md +0 -76
- package/template/agent/skills/rust-developer/references/rust-rules/name-into-ownership.md +0 -123
- package/template/agent/skills/rust-developer/references/rust-rules/name-is-has-bool.md +0 -127
- package/template/agent/skills/rust-developer/references/rust-rules/name-iter-convention.md +0 -129
- package/template/agent/skills/rust-developer/references/rust-rules/name-iter-method.md +0 -131
- package/template/agent/skills/rust-developer/references/rust-rules/name-iter-type-match.md +0 -142
- package/template/agent/skills/rust-developer/references/rust-rules/name-lifetime-short.md +0 -86
- package/template/agent/skills/rust-developer/references/rust-rules/name-no-get-prefix.md +0 -154
- package/template/agent/skills/rust-developer/references/rust-rules/name-to-expensive.md +0 -118
- package/template/agent/skills/rust-developer/references/rust-rules/name-type-param-single.md +0 -92
- package/template/agent/skills/rust-developer/references/rust-rules/name-types-camel.md +0 -65
- package/template/agent/skills/rust-developer/references/rust-rules/name-variants-camel.md +0 -101
- package/template/agent/skills/rust-developer/references/rust-rules/opt-bounds-check.md +0 -161
- package/template/agent/skills/rust-developer/references/rust-rules/opt-cache-friendly.md +0 -187
- package/template/agent/skills/rust-developer/references/rust-rules/opt-codegen-units.md +0 -142
- package/template/agent/skills/rust-developer/references/rust-rules/opt-cold-unlikely.md +0 -152
- package/template/agent/skills/rust-developer/references/rust-rules/opt-inline-always-rare.md +0 -141
- package/template/agent/skills/rust-developer/references/rust-rules/opt-inline-never-cold.md +0 -181
- package/template/agent/skills/rust-developer/references/rust-rules/opt-inline-small.md +0 -160
- package/template/agent/skills/rust-developer/references/rust-rules/opt-likely-hint.md +0 -171
- package/template/agent/skills/rust-developer/references/rust-rules/opt-lto-release.md +0 -130
- package/template/agent/skills/rust-developer/references/rust-rules/opt-pgo-profile.md +0 -167
- package/template/agent/skills/rust-developer/references/rust-rules/opt-simd-portable.md +0 -144
- package/template/agent/skills/rust-developer/references/rust-rules/opt-target-cpu.md +0 -154
- package/template/agent/skills/rust-developer/references/rust-rules/own-arc-shared.md +0 -141
- package/template/agent/skills/rust-developer/references/rust-rules/own-borrow-over-clone.md +0 -95
- package/template/agent/skills/rust-developer/references/rust-rules/own-clone-explicit.md +0 -135
- package/template/agent/skills/rust-developer/references/rust-rules/own-copy-small.md +0 -124
- package/template/agent/skills/rust-developer/references/rust-rules/own-cow-conditional.md +0 -135
- package/template/agent/skills/rust-developer/references/rust-rules/own-lifetime-elision.md +0 -134
- package/template/agent/skills/rust-developer/references/rust-rules/own-move-large.md +0 -134
- package/template/agent/skills/rust-developer/references/rust-rules/own-mutex-interior.md +0 -105
- package/template/agent/skills/rust-developer/references/rust-rules/own-rc-single-thread.md +0 -65
- package/template/agent/skills/rust-developer/references/rust-rules/own-refcell-interior.md +0 -97
- package/template/agent/skills/rust-developer/references/rust-rules/own-rwlock-readers.md +0 -122
- package/template/agent/skills/rust-developer/references/rust-rules/own-slice-over-vec.md +0 -119
- package/template/agent/skills/rust-developer/references/rust-rules/perf-black-box-bench.md +0 -153
- package/template/agent/skills/rust-developer/references/rust-rules/perf-chain-avoid.md +0 -136
- package/template/agent/skills/rust-developer/references/rust-rules/perf-collect-into.md +0 -133
- package/template/agent/skills/rust-developer/references/rust-rules/perf-collect-once.md +0 -120
- package/template/agent/skills/rust-developer/references/rust-rules/perf-drain-reuse.md +0 -137
- package/template/agent/skills/rust-developer/references/rust-rules/perf-entry-api.md +0 -134
- package/template/agent/skills/rust-developer/references/rust-rules/perf-extend-batch.md +0 -150
- package/template/agent/skills/rust-developer/references/rust-rules/perf-iter-lazy.md +0 -123
- package/template/agent/skills/rust-developer/references/rust-rules/perf-iter-over-index.md +0 -113
- package/template/agent/skills/rust-developer/references/rust-rules/perf-profile-first.md +0 -175
- package/template/agent/skills/rust-developer/references/rust-rules/perf-release-profile.md +0 -149
- package/template/agent/skills/rust-developer/references/rust-rules/proj-bin-dir.md +0 -142
- package/template/agent/skills/rust-developer/references/rust-rules/proj-flat-small.md +0 -133
- package/template/agent/skills/rust-developer/references/rust-rules/proj-lib-main-split.md +0 -148
- package/template/agent/skills/rust-developer/references/rust-rules/proj-mod-by-feature.md +0 -130
- package/template/agent/skills/rust-developer/references/rust-rules/proj-mod-rs-dir.md +0 -120
- package/template/agent/skills/rust-developer/references/rust-rules/proj-prelude-module.md +0 -155
- package/template/agent/skills/rust-developer/references/rust-rules/proj-pub-crate-internal.md +0 -139
- package/template/agent/skills/rust-developer/references/rust-rules/proj-pub-super-parent.md +0 -135
- package/template/agent/skills/rust-developer/references/rust-rules/proj-pub-use-reexport.md +0 -162
- package/template/agent/skills/rust-developer/references/rust-rules/proj-workspace-deps.md +0 -186
- package/template/agent/skills/rust-developer/references/rust-rules/proj-workspace-large.md +0 -162
- package/template/agent/skills/rust-developer/references/rust-rules/test-arrange-act-assert.md +0 -160
- package/template/agent/skills/rust-developer/references/rust-rules/test-cfg-test-module.md +0 -151
- package/template/agent/skills/rust-developer/references/rust-rules/test-criterion-bench.md +0 -171
- package/template/agent/skills/rust-developer/references/rust-rules/test-descriptive-names.md +0 -142
- package/template/agent/skills/rust-developer/references/rust-rules/test-doctest-examples.md +0 -168
- package/template/agent/skills/rust-developer/references/rust-rules/test-fixture-raii.md +0 -151
- package/template/agent/skills/rust-developer/references/rust-rules/test-integration-dir.md +0 -144
- package/template/agent/skills/rust-developer/references/rust-rules/test-mock-traits.md +0 -189
- package/template/agent/skills/rust-developer/references/rust-rules/test-mockall-mocking.md +0 -226
- package/template/agent/skills/rust-developer/references/rust-rules/test-proptest-properties.md +0 -161
- package/template/agent/skills/rust-developer/references/rust-rules/test-should-panic.md +0 -130
- package/template/agent/skills/rust-developer/references/rust-rules/test-tokio-async.md +0 -154
- package/template/agent/skills/rust-developer/references/rust-rules/test-use-super.md +0 -127
- package/template/agent/skills/rust-developer/references/rust-rules/type-enum-states.md +0 -154
- package/template/agent/skills/rust-developer/references/rust-rules/type-generic-bounds.md +0 -142
- package/template/agent/skills/rust-developer/references/rust-rules/type-never-diverge.md +0 -146
- package/template/agent/skills/rust-developer/references/rust-rules/type-newtype-ids.md +0 -160
- package/template/agent/skills/rust-developer/references/rust-rules/type-newtype-validated.md +0 -159
- package/template/agent/skills/rust-developer/references/rust-rules/type-no-stringly.md +0 -144
- package/template/agent/skills/rust-developer/references/rust-rules/type-option-nullable.md +0 -137
- package/template/agent/skills/rust-developer/references/rust-rules/type-phantom-marker.md +0 -188
- package/template/agent/skills/rust-developer/references/rust-rules/type-repr-transparent.md +0 -143
- package/template/agent/skills/rust-developer/references/rust-rules/type-result-fallible.md +0 -131
- package/template/agent/skills/saas-architect/SKILL.md +0 -139
- package/template/agent/skills/security-engineer/SKILL.md +0 -133
- package/template/agent/skills/seo-specialist/SKILL.md +0 -130
- package/template/agent/skills/solo-founder-ops/SKILL.md +0 -56
|
@@ -1,124 +0,0 @@
|
|
|
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
|
package/template/agent/skills/rust-developer/references/rust-rules/anti-collect-intermediate.md
DELETED
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
# anti-collect-intermediate
|
|
2
|
-
|
|
3
|
-
> Don't collect intermediate iterators
|
|
4
|
-
|
|
5
|
-
## Why It Matters
|
|
6
|
-
|
|
7
|
-
Each `.collect()` allocates a new collection. Collecting intermediate results in a chain creates unnecessary allocations and prevents iterator fusion. Keep the chain lazy; collect only at the end.
|
|
8
|
-
|
|
9
|
-
## Bad
|
|
10
|
-
|
|
11
|
-
```rust
|
|
12
|
-
// Three allocations, three passes
|
|
13
|
-
fn process(data: Vec<i32>) -> Vec<i32> {
|
|
14
|
-
let step1: Vec<_> = data.into_iter()
|
|
15
|
-
.filter(|x| *x > 0)
|
|
16
|
-
.collect();
|
|
17
|
-
|
|
18
|
-
let step2: Vec<_> = step1.into_iter()
|
|
19
|
-
.map(|x| x * 2)
|
|
20
|
-
.collect();
|
|
21
|
-
|
|
22
|
-
step2.into_iter()
|
|
23
|
-
.filter(|x| *x < 100)
|
|
24
|
-
.collect()
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// Collecting just to check length
|
|
28
|
-
fn has_valid_items(items: &[Item]) -> bool {
|
|
29
|
-
let valid: Vec<_> = items.iter()
|
|
30
|
-
.filter(|i| i.is_valid())
|
|
31
|
-
.collect();
|
|
32
|
-
!valid.is_empty()
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// Collecting to iterate again
|
|
36
|
-
fn sum_valid(items: &[Item]) -> i64 {
|
|
37
|
-
let valid: Vec<_> = items.iter()
|
|
38
|
-
.filter(|i| i.is_valid())
|
|
39
|
-
.collect();
|
|
40
|
-
valid.iter().map(|i| i.value).sum()
|
|
41
|
-
}
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
## Good
|
|
45
|
-
|
|
46
|
-
```rust
|
|
47
|
-
// Single allocation, single pass
|
|
48
|
-
fn process(data: Vec<i32>) -> Vec<i32> {
|
|
49
|
-
data.into_iter()
|
|
50
|
-
.filter(|x| *x > 0)
|
|
51
|
-
.map(|x| x * 2)
|
|
52
|
-
.filter(|x| *x < 100)
|
|
53
|
-
.collect()
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// No allocation - iterator short-circuits
|
|
57
|
-
fn has_valid_items(items: &[Item]) -> bool {
|
|
58
|
-
items.iter().any(|i| i.is_valid())
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// No intermediate allocation
|
|
62
|
-
fn sum_valid(items: &[Item]) -> i64 {
|
|
63
|
-
items.iter()
|
|
64
|
-
.filter(|i| i.is_valid())
|
|
65
|
-
.map(|i| i.value)
|
|
66
|
-
.sum()
|
|
67
|
-
}
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
## When Collection Is Needed
|
|
71
|
-
|
|
72
|
-
```rust
|
|
73
|
-
// Need to iterate twice
|
|
74
|
-
let valid: Vec<_> = items.iter()
|
|
75
|
-
.filter(|i| i.is_valid())
|
|
76
|
-
.collect();
|
|
77
|
-
let count = valid.len();
|
|
78
|
-
for item in &valid {
|
|
79
|
-
process(item);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// Need to sort (requires concrete collection)
|
|
83
|
-
let mut sorted: Vec<_> = items.iter()
|
|
84
|
-
.filter(|i| i.is_active())
|
|
85
|
-
.collect();
|
|
86
|
-
sorted.sort_by_key(|i| i.priority);
|
|
87
|
-
|
|
88
|
-
// Need random access
|
|
89
|
-
let indexed: Vec<_> = items.iter().collect();
|
|
90
|
-
let middle = indexed.get(indexed.len() / 2);
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
## Iterator Methods That Avoid Collection
|
|
94
|
-
|
|
95
|
-
| Instead of Collecting to... | Use |
|
|
96
|
-
|-----------------------------|-----|
|
|
97
|
-
| Check if empty | `.any(|_| true)` or `.next().is_some()` |
|
|
98
|
-
| Check if any match | `.any(predicate)` |
|
|
99
|
-
| Check if all match | `.all(predicate)` |
|
|
100
|
-
| Count elements | `.count()` |
|
|
101
|
-
| Sum elements | `.sum()` |
|
|
102
|
-
| Find first | `.find(predicate)` |
|
|
103
|
-
| Get first | `.next()` |
|
|
104
|
-
| Get last | `.last()` |
|
|
105
|
-
|
|
106
|
-
## Pattern: Deferred Collection
|
|
107
|
-
|
|
108
|
-
```rust
|
|
109
|
-
// Return iterator, let caller collect if needed
|
|
110
|
-
fn valid_items(items: &[Item]) -> impl Iterator<Item = &Item> {
|
|
111
|
-
items.iter().filter(|i| i.is_valid())
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
// Caller decides
|
|
115
|
-
let count = valid_items(&items).count(); // No collection
|
|
116
|
-
let vec: Vec<_> = valid_items(&items).collect(); // Collection when needed
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
## Comparison
|
|
120
|
-
|
|
121
|
-
| Pattern | Allocations | Passes |
|
|
122
|
-
|---------|-------------|--------|
|
|
123
|
-
| `.collect()` each step | N | N |
|
|
124
|
-
| Single chain, one `.collect()` | 1 | 1 |
|
|
125
|
-
| No collection (streaming) | 0 | 1 |
|
|
126
|
-
|
|
127
|
-
## See Also
|
|
128
|
-
|
|
129
|
-
- [perf-collect-once](./perf-collect-once.md) - Single collect
|
|
130
|
-
- [perf-iter-lazy](./perf-iter-lazy.md) - Lazy evaluation
|
|
131
|
-
- [perf-iter-over-index](./perf-iter-over-index.md) - Iterator patterns
|
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
# anti-empty-catch
|
|
2
|
-
|
|
3
|
-
> Don't silently ignore errors
|
|
4
|
-
|
|
5
|
-
## Why It Matters
|
|
6
|
-
|
|
7
|
-
Empty error handling (`if let Err(_) = ...`, `let _ = result`, `.ok()`) silently discards errors. Failures go unnoticed, bugs hide, and debugging becomes impossible. Every error deserves acknowledgment—even if just logging.
|
|
8
|
-
|
|
9
|
-
## Bad
|
|
10
|
-
|
|
11
|
-
```rust
|
|
12
|
-
// Silently ignores errors
|
|
13
|
-
let _ = write_to_file(data);
|
|
14
|
-
|
|
15
|
-
// Discards error completely
|
|
16
|
-
if let Err(_) = send_notification() {
|
|
17
|
-
// Nothing - error vanishes
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
// Converts Result to Option, losing error info
|
|
21
|
-
let value = risky_operation().ok();
|
|
22
|
-
|
|
23
|
-
// Match with empty arm
|
|
24
|
-
match database.save(record) {
|
|
25
|
-
Ok(_) => println!("saved"),
|
|
26
|
-
Err(_) => {} // Silent failure
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// Ignored in loop
|
|
30
|
-
for item in items {
|
|
31
|
-
let _ = process(item); // Failures unnoticed
|
|
32
|
-
}
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
## Good
|
|
36
|
-
|
|
37
|
-
```rust
|
|
38
|
-
// Log the error
|
|
39
|
-
if let Err(e) = write_to_file(data) {
|
|
40
|
-
error!("failed to write file: {}", e);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// Propagate if possible
|
|
44
|
-
send_notification()?;
|
|
45
|
-
|
|
46
|
-
// Or handle explicitly
|
|
47
|
-
match send_notification() {
|
|
48
|
-
Ok(_) => info!("notification sent"),
|
|
49
|
-
Err(e) => warn!("notification failed: {}", e),
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// Collect errors in batch operations
|
|
53
|
-
let (successes, failures): (Vec<_>, Vec<_>) = items
|
|
54
|
-
.into_iter()
|
|
55
|
-
.map(process)
|
|
56
|
-
.partition(Result::is_ok);
|
|
57
|
-
|
|
58
|
-
if !failures.is_empty() {
|
|
59
|
-
warn!("{} items failed to process", failures.len());
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// Explicit documentation when ignoring
|
|
63
|
-
// Intentionally ignored: cleanup failure is not critical
|
|
64
|
-
let _ = cleanup_temp_file(); // Add comment explaining why
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
## Acceptable Ignoring (Documented)
|
|
68
|
-
|
|
69
|
-
```rust
|
|
70
|
-
// Close errors often ignored, but document it
|
|
71
|
-
// INTENTIONAL: TCP close errors are not actionable
|
|
72
|
-
let _ = stream.shutdown(Shutdown::Both);
|
|
73
|
-
|
|
74
|
-
// Mutex poisoning recovery
|
|
75
|
-
// INTENTIONAL: We'll reset the state anyway
|
|
76
|
-
let guard = mutex.lock().unwrap_or_else(|e| e.into_inner());
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
## Pattern: Collect and Report
|
|
80
|
-
|
|
81
|
-
```rust
|
|
82
|
-
fn process_batch(items: Vec<Item>) -> BatchResult {
|
|
83
|
-
let mut errors = Vec::new();
|
|
84
|
-
|
|
85
|
-
for item in items {
|
|
86
|
-
if let Err(e) = process_item(&item) {
|
|
87
|
-
errors.push((item.id, e));
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
if errors.is_empty() {
|
|
92
|
-
BatchResult::AllSucceeded
|
|
93
|
-
} else {
|
|
94
|
-
BatchResult::PartialFailure(errors)
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
## Pattern: Best-Effort Operations
|
|
100
|
-
|
|
101
|
-
```rust
|
|
102
|
-
// Metrics/telemetry can fail without affecting main flow
|
|
103
|
-
fn report_metric(name: &str, value: f64) {
|
|
104
|
-
if let Err(e) = metrics_client.record(name, value) {
|
|
105
|
-
// Log but don't propagate - metrics are not critical
|
|
106
|
-
debug!("failed to record metric {}: {}", name, e);
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
## Clippy Lint
|
|
112
|
-
|
|
113
|
-
```toml
|
|
114
|
-
[lints.clippy]
|
|
115
|
-
let_underscore_drop = "warn"
|
|
116
|
-
ignored_unit_patterns = "warn"
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
## Decision Guide
|
|
120
|
-
|
|
121
|
-
| Situation | Action |
|
|
122
|
-
|-----------|--------|
|
|
123
|
-
| Critical operation | `?` or handle explicitly |
|
|
124
|
-
| Non-critical, debugging needed | Log the error |
|
|
125
|
-
| Truly ignorable (rare) | `let _ =` with comment |
|
|
126
|
-
| Batch operation | Collect errors, report |
|
|
127
|
-
|
|
128
|
-
## See Also
|
|
129
|
-
|
|
130
|
-
- [err-result-over-panic](./err-result-over-panic.md) - Proper error handling
|
|
131
|
-
- [err-context-chain](./err-context-chain.md) - Adding context
|
|
132
|
-
- [anti-unwrap-abuse](./anti-unwrap-abuse.md) - Unwrap issues
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
# anti-expect-lazy
|
|
2
|
-
|
|
3
|
-
> Don't use expect for recoverable errors
|
|
4
|
-
|
|
5
|
-
## Why It Matters
|
|
6
|
-
|
|
7
|
-
`.expect()` panics with a custom message, but it's still a panic. Using it for errors that could reasonably occur in production (network failures, file not found, invalid input) crashes the program instead of handling the error gracefully.
|
|
8
|
-
|
|
9
|
-
Reserve `.expect()` for programming errors where panic is appropriate.
|
|
10
|
-
|
|
11
|
-
## Bad
|
|
12
|
-
|
|
13
|
-
```rust
|
|
14
|
-
// Network failures are expected - don't panic
|
|
15
|
-
let response = client.get(url).await.expect("failed to fetch");
|
|
16
|
-
|
|
17
|
-
// Files might not exist
|
|
18
|
-
let config = fs::read_to_string("config.toml").expect("config not found");
|
|
19
|
-
|
|
20
|
-
// User input can be invalid
|
|
21
|
-
let age: u32 = input.parse().expect("invalid age");
|
|
22
|
-
|
|
23
|
-
// Database queries can fail
|
|
24
|
-
let user = db.find_user(id).await.expect("user not found");
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
## Good
|
|
28
|
-
|
|
29
|
-
```rust
|
|
30
|
-
// Handle recoverable errors properly
|
|
31
|
-
let response = client.get(url).await
|
|
32
|
-
.context("failed to fetch URL")?;
|
|
33
|
-
|
|
34
|
-
// Return error if file doesn't exist
|
|
35
|
-
let config = fs::read_to_string("config.toml")
|
|
36
|
-
.context("failed to read config file")?;
|
|
37
|
-
|
|
38
|
-
// Validate and return error
|
|
39
|
-
let age: u32 = input.parse()
|
|
40
|
-
.map_err(|_| Error::InvalidInput("age must be a number"))?;
|
|
41
|
-
|
|
42
|
-
// Handle missing data
|
|
43
|
-
let user = db.find_user(id).await?
|
|
44
|
-
.ok_or(Error::NotFound("user"))?;
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
## When expect() Is Appropriate
|
|
48
|
-
|
|
49
|
-
Use `.expect()` for invariants that indicate bugs:
|
|
50
|
-
|
|
51
|
-
```rust
|
|
52
|
-
// Mutex poisoning indicates a bug elsewhere
|
|
53
|
-
let guard = mutex.lock().expect("mutex poisoned");
|
|
54
|
-
|
|
55
|
-
// Regex is known valid at compile time
|
|
56
|
-
let re = Regex::new(r"^\d{4}$").expect("invalid regex");
|
|
57
|
-
|
|
58
|
-
// Thread spawn failure is unrecoverable
|
|
59
|
-
let handle = thread::spawn(|| work()).expect("failed to spawn thread");
|
|
60
|
-
|
|
61
|
-
// Static data that must be valid
|
|
62
|
-
let config: Config = toml::from_str(EMBEDDED_CONFIG)
|
|
63
|
-
.expect("embedded config is invalid");
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
## Pattern: expect() vs unwrap()
|
|
67
|
-
|
|
68
|
-
```rust
|
|
69
|
-
// unwrap: no context, hard to debug
|
|
70
|
-
let x = option.unwrap();
|
|
71
|
-
|
|
72
|
-
// expect: gives context, still panics
|
|
73
|
-
let x = option.expect("value should exist after validation");
|
|
74
|
-
|
|
75
|
-
// ?: proper error handling
|
|
76
|
-
let x = option.ok_or(Error::MissingValue)?;
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
## Decision Guide
|
|
80
|
-
|
|
81
|
-
| Situation | Use |
|
|
82
|
-
|-----------|-----|
|
|
83
|
-
| User input | `?` with error |
|
|
84
|
-
| File/network I/O | `?` with error |
|
|
85
|
-
| Database operations | `?` with error |
|
|
86
|
-
| Parsed constants | `.expect()` |
|
|
87
|
-
| Thread/mutex operations | `.expect()` |
|
|
88
|
-
| After validation check | `.expect()` with explanation |
|
|
89
|
-
| Never expected to fail | `.expect()` documenting invariant |
|
|
90
|
-
|
|
91
|
-
## See Also
|
|
92
|
-
|
|
93
|
-
- [err-expect-bugs-only](./err-expect-bugs-only.md) - When to use expect
|
|
94
|
-
- [err-no-unwrap-prod](./err-no-unwrap-prod.md) - Avoiding unwrap
|
|
95
|
-
- [anti-unwrap-abuse](./anti-unwrap-abuse.md) - Unwrap anti-pattern
|
|
@@ -1,141 +0,0 @@
|
|
|
1
|
-
# anti-format-hot-path
|
|
2
|
-
|
|
3
|
-
> Don't use format! in hot paths
|
|
4
|
-
|
|
5
|
-
## Why It Matters
|
|
6
|
-
|
|
7
|
-
`format!()` allocates a new `String` every call. In hot paths (loops, frequently called functions), this creates allocation churn that impacts performance. Pre-allocate, reuse buffers, or use `write!()` to an existing buffer.
|
|
8
|
-
|
|
9
|
-
## Bad
|
|
10
|
-
|
|
11
|
-
```rust
|
|
12
|
-
// format! in loop - allocates every iteration
|
|
13
|
-
fn log_events(events: &[Event]) {
|
|
14
|
-
for event in events {
|
|
15
|
-
let message = format!("[{}] {}: {}", event.level, event.source, event.message);
|
|
16
|
-
logger.log(&message);
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
// format! for building parts
|
|
21
|
-
fn build_url(base: &str, path: &str, params: &[(&str, &str)]) -> String {
|
|
22
|
-
let mut url = format!("{}{}", base, path);
|
|
23
|
-
for (key, value) in params {
|
|
24
|
-
url = format!("{}{}={}&", url, key, value); // New allocation each time
|
|
25
|
-
}
|
|
26
|
-
url
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// format! for simple concatenation
|
|
30
|
-
fn greet(name: &str) -> String {
|
|
31
|
-
format!("Hello, {}!", name) // Fine for one-off, bad if called 1M times
|
|
32
|
-
}
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
## Good
|
|
36
|
-
|
|
37
|
-
```rust
|
|
38
|
-
use std::fmt::Write;
|
|
39
|
-
|
|
40
|
-
// Reuse buffer across iterations
|
|
41
|
-
fn log_events(events: &[Event]) {
|
|
42
|
-
let mut buffer = String::with_capacity(256);
|
|
43
|
-
for event in events {
|
|
44
|
-
buffer.clear();
|
|
45
|
-
write!(buffer, "[{}] {}: {}", event.level, event.source, event.message).unwrap();
|
|
46
|
-
logger.log(&buffer);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// Build incrementally in single buffer
|
|
51
|
-
fn build_url(base: &str, path: &str, params: &[(&str, &str)]) -> String {
|
|
52
|
-
let mut url = String::with_capacity(base.len() + path.len() + params.len() * 20);
|
|
53
|
-
url.push_str(base);
|
|
54
|
-
url.push_str(path);
|
|
55
|
-
for (key, value) in params {
|
|
56
|
-
write!(url, "{}={}&", key, value).unwrap();
|
|
57
|
-
}
|
|
58
|
-
url
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// For truly hot paths, avoid allocation entirely
|
|
62
|
-
fn greet_to_buf(name: &str, buffer: &mut String) {
|
|
63
|
-
buffer.clear();
|
|
64
|
-
buffer.push_str("Hello, ");
|
|
65
|
-
buffer.push_str(name);
|
|
66
|
-
buffer.push('!');
|
|
67
|
-
}
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
## Comparison
|
|
71
|
-
|
|
72
|
-
| Approach | Allocations | Performance |
|
|
73
|
-
|----------|-------------|-------------|
|
|
74
|
-
| `format!()` in loop | N | Slow |
|
|
75
|
-
| `write!()` to reused buffer | 1 | Fast |
|
|
76
|
-
| `push_str()` + `push()` | 1 | Fastest |
|
|
77
|
-
| Pre-sized `String::with_capacity()` | 1 (no realloc) | Fast |
|
|
78
|
-
|
|
79
|
-
## When format! Is Fine
|
|
80
|
-
|
|
81
|
-
```rust
|
|
82
|
-
// One-time initialization
|
|
83
|
-
let config_path = format!("{}/config.toml", home_dir);
|
|
84
|
-
|
|
85
|
-
// Error messages (not hot path)
|
|
86
|
-
return Err(format!("invalid input: {}", input));
|
|
87
|
-
|
|
88
|
-
// Debug output
|
|
89
|
-
println!("Debug: {:?}", value);
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
## Pattern: Formatter Buffer Pool
|
|
93
|
-
|
|
94
|
-
```rust
|
|
95
|
-
use std::cell::RefCell;
|
|
96
|
-
|
|
97
|
-
thread_local! {
|
|
98
|
-
static BUFFER: RefCell<String> = RefCell::new(String::with_capacity(256));
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
fn format_event(event: &Event) -> String {
|
|
102
|
-
BUFFER.with(|buf| {
|
|
103
|
-
let mut buf = buf.borrow_mut();
|
|
104
|
-
buf.clear();
|
|
105
|
-
write!(buf, "[{}] {}", event.level, event.message).unwrap();
|
|
106
|
-
buf.clone() // Still one allocation per call, but no parsing
|
|
107
|
-
})
|
|
108
|
-
}
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
## Pattern: Display Implementation
|
|
112
|
-
|
|
113
|
-
```rust
|
|
114
|
-
struct Event {
|
|
115
|
-
level: Level,
|
|
116
|
-
message: String,
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
impl std::fmt::Display for Event {
|
|
120
|
-
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
121
|
-
write!(f, "[{}] {}", self.level, self.message)
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
// Caller controls allocation
|
|
126
|
-
let mut buf = String::new();
|
|
127
|
-
write!(buf, "{}", event)?;
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
## Clippy Lint
|
|
131
|
-
|
|
132
|
-
```toml
|
|
133
|
-
[lints.clippy]
|
|
134
|
-
format_in_format_args = "warn"
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
## See Also
|
|
138
|
-
|
|
139
|
-
- [mem-avoid-format](./mem-avoid-format.md) - Avoiding format
|
|
140
|
-
- [mem-write-over-format](./mem-write-over-format.md) - Using write!
|
|
141
|
-
- [mem-reuse-collections](./mem-reuse-collections.md) - Buffer reuse
|