agy-superpowers 5.2.1 → 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/patches/skills-patches.md +23 -0
- package/template/agent/rules/scratch-scripts.md +37 -0
- package/template/agent/rules/superpowers.md +6 -50
- package/template/agent/skills/brainstorming/SKILL.md +4 -3
- package/template/agent/skills/brainstorming/visual-companion.md +2 -3
- package/template/agent/skills/finishing-a-development-branch/SKILL.md +11 -16
- package/template/agent/skills/subagent-driven-development/SKILL.md +16 -0
- package/template/agent/skills/subagent-driven-development/implementer-prompt.md +4 -3
- package/template/agent/skills/using-git-worktrees/SKILL.md +3 -2
- package/template/agent/skills/using-superpowers/SKILL.md +8 -6
- package/template/agent/skills/using-superpowers/references/copilot-tools.md +52 -0
- package/template/agent/skills/writing-plans/SKILL.md +5 -3
- package/template/agent/skills/writing-skills/SKILL.md +1 -1
- package/template/agent/superpowers-version.json +2 -2
- package/template/agent/tmp/agent-config-backup.yml +9 -0
- 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
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
|
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
# anti-index-over-iter
|
|
2
|
-
|
|
3
|
-
> Don't use indexing when iterators work
|
|
4
|
-
|
|
5
|
-
## Why It Matters
|
|
6
|
-
|
|
7
|
-
Manual indexing (`for i in 0..len`) requires bounds checks on every access, prevents SIMD optimization, and introduces off-by-one error risks. Iterators eliminate these issues and are more idiomatic Rust.
|
|
8
|
-
|
|
9
|
-
## Bad
|
|
10
|
-
|
|
11
|
-
```rust
|
|
12
|
-
// Manual indexing - bounds checked every access
|
|
13
|
-
fn sum_squares(data: &[i32]) -> i64 {
|
|
14
|
-
let mut result = 0i64;
|
|
15
|
-
for i in 0..data.len() {
|
|
16
|
-
result += (data[i] as i64) * (data[i] as i64);
|
|
17
|
-
}
|
|
18
|
-
result
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
// Index-based with multiple arrays
|
|
22
|
-
fn dot_product(a: &[f64], b: &[f64]) -> f64 {
|
|
23
|
-
let mut sum = 0.0;
|
|
24
|
-
for i in 0..a.len().min(b.len()) {
|
|
25
|
-
sum += a[i] * b[i];
|
|
26
|
-
}
|
|
27
|
-
sum
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// Mutation with indices
|
|
31
|
-
fn normalize(data: &mut [f64]) {
|
|
32
|
-
let max = data.iter().cloned().fold(0.0, f64::max);
|
|
33
|
-
for i in 0..data.len() {
|
|
34
|
-
data[i] /= max;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
## Good
|
|
40
|
-
|
|
41
|
-
```rust
|
|
42
|
-
// Iterator - no bounds checks, SIMD-friendly
|
|
43
|
-
fn sum_squares(data: &[i32]) -> i64 {
|
|
44
|
-
data.iter()
|
|
45
|
-
.map(|&x| (x as i64) * (x as i64))
|
|
46
|
-
.sum()
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// Zip - handles length mismatch automatically
|
|
50
|
-
fn dot_product(a: &[f64], b: &[f64]) -> f64 {
|
|
51
|
-
a.iter()
|
|
52
|
-
.zip(b.iter())
|
|
53
|
-
.map(|(&x, &y)| x * y)
|
|
54
|
-
.sum()
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// Mutable iteration
|
|
58
|
-
fn normalize(data: &mut [f64]) {
|
|
59
|
-
let max = data.iter().cloned().fold(0.0, f64::max);
|
|
60
|
-
for x in data.iter_mut() {
|
|
61
|
-
*x /= max;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
## When Indices Are Needed
|
|
67
|
-
|
|
68
|
-
Sometimes you genuinely need indices:
|
|
69
|
-
|
|
70
|
-
```rust
|
|
71
|
-
// Need index in output
|
|
72
|
-
for (i, item) in items.iter().enumerate() {
|
|
73
|
-
println!("{}: {}", i, item);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// Non-sequential access
|
|
77
|
-
for i in (0..len).step_by(2) {
|
|
78
|
-
swap(&mut data[i], &mut data[i + 1]);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// Multi-dimensional iteration
|
|
82
|
-
for i in 0..rows {
|
|
83
|
-
for j in 0..cols {
|
|
84
|
-
matrix[i][j] = i * cols + j;
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
## Comparison
|
|
90
|
-
|
|
91
|
-
| Pattern | Bounds Checks | SIMD | Safety |
|
|
92
|
-
|---------|---------------|------|--------|
|
|
93
|
-
| `for i in 0..len { data[i] }` | Every access | Limited | Off-by-one risk |
|
|
94
|
-
| `for x in &data` | None | Good | Safe |
|
|
95
|
-
| `for x in data.iter()` | None | Good | Safe |
|
|
96
|
-
| `data.iter().enumerate()` | None | Good | Safe |
|
|
97
|
-
|
|
98
|
-
## Common Conversions
|
|
99
|
-
|
|
100
|
-
| Index Pattern | Iterator Pattern |
|
|
101
|
-
|---------------|------------------|
|
|
102
|
-
| `for i in 0..v.len()` | `for x in &v` |
|
|
103
|
-
| `v[0]` | `v.first()` |
|
|
104
|
-
| `v[v.len()-1]` | `v.last()` |
|
|
105
|
-
| `for i in 0..a.len() { a[i] + b[i] }` | `a.iter().zip(&b)` |
|
|
106
|
-
| `for i in 0..v.len() { v[i] *= 2 }` | `for x in &mut v { *x *= 2 }` |
|
|
107
|
-
|
|
108
|
-
## Performance Note
|
|
109
|
-
|
|
110
|
-
```rust
|
|
111
|
-
// Iterator version can auto-vectorize
|
|
112
|
-
let sum: i32 = data.iter().sum();
|
|
113
|
-
|
|
114
|
-
// Manual indexing prevents vectorization
|
|
115
|
-
let mut sum = 0;
|
|
116
|
-
for i in 0..data.len() {
|
|
117
|
-
sum += data[i];
|
|
118
|
-
}
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
## See Also
|
|
122
|
-
|
|
123
|
-
- [perf-iter-over-index](./perf-iter-over-index.md) - Performance details
|
|
124
|
-
- [opt-bounds-check](./opt-bounds-check.md) - Bounds check elimination
|
|
125
|
-
- [perf-iter-lazy](./perf-iter-lazy.md) - Lazy iterators
|