agy-superpowers 5.2.2 → 5.2.4
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/CLAUDE.md +80 -0
- package/template/agent/rules/code-styles.md +31 -32
- package/template/agent/rules/debug-confirmation-policy.md +2 -0
- package/template/agent/rules/file-length-policy.md +2 -0
- package/template/agent/rules/git-policy.md +7 -0
- package/template/agent/rules/language-matching.md +2 -0
- package/template/agent/rules/scratch-scripts.md +39 -0
- package/template/agent/rules/superpowers.md +8 -51
- package/template/agent/skills/executing-plans/SKILL.md +17 -0
- package/template/agent/skills/systematic-debugging/SKILL.md +16 -0
- package/template/agent/skills/test-driven-development/SKILL.md +16 -0
- package/template/agent/skills/verification-before-completion/SKILL.md +22 -0
- package/template/agent/skills/writing-plans/SKILL.md +16 -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
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
# perf-collect-into
|
|
2
|
-
|
|
3
|
-
> Use collect_into for reusing containers
|
|
4
|
-
|
|
5
|
-
## Why It Matters
|
|
6
|
-
|
|
7
|
-
`collect_into()` (stabilized in Rust 1.83) allows collecting iterator results into an existing collection, reusing its allocation. This avoids the allocation that `collect()` would make for a new collection.
|
|
8
|
-
|
|
9
|
-
## Bad
|
|
10
|
-
|
|
11
|
-
```rust
|
|
12
|
-
// Allocates new Vec each time
|
|
13
|
-
fn process_batches(batches: Vec<Vec<i32>>) -> Vec<Vec<i32>> {
|
|
14
|
-
batches.into_iter()
|
|
15
|
-
.map(|batch| {
|
|
16
|
-
batch.into_iter()
|
|
17
|
-
.filter(|x| *x > 0)
|
|
18
|
-
.collect::<Vec<_>>() // New allocation per batch
|
|
19
|
-
})
|
|
20
|
-
.collect()
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
// Can't reuse cleared buffer
|
|
24
|
-
fn filter_loop(data: &[Vec<i32>]) {
|
|
25
|
-
for batch in data {
|
|
26
|
-
let filtered: Vec<_> = batch.iter()
|
|
27
|
-
.filter(|&&x| x > 0)
|
|
28
|
-
.copied()
|
|
29
|
-
.collect(); // New allocation each iteration
|
|
30
|
-
process(&filtered);
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
## Good
|
|
36
|
-
|
|
37
|
-
```rust
|
|
38
|
-
// Reuse buffer with collect_into
|
|
39
|
-
fn filter_loop(data: &[Vec<i32>]) {
|
|
40
|
-
let mut buffer = Vec::new();
|
|
41
|
-
|
|
42
|
-
for batch in data {
|
|
43
|
-
buffer.clear(); // Keep allocation
|
|
44
|
-
batch.iter()
|
|
45
|
-
.filter(|&&x| x > 0)
|
|
46
|
-
.copied()
|
|
47
|
-
.collect_into(&mut buffer);
|
|
48
|
-
process(&buffer);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// Also works with extend pattern
|
|
53
|
-
fn filter_loop_extend(data: &[Vec<i32>]) {
|
|
54
|
-
let mut buffer = Vec::new();
|
|
55
|
-
|
|
56
|
-
for batch in data {
|
|
57
|
-
buffer.clear();
|
|
58
|
-
buffer.extend(
|
|
59
|
-
batch.iter()
|
|
60
|
-
.filter(|&&x| x > 0)
|
|
61
|
-
.copied()
|
|
62
|
-
);
|
|
63
|
-
process(&buffer);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
## Pre-1.83 Alternative: extend
|
|
69
|
-
|
|
70
|
-
Before `collect_into()` was stabilized, use `extend()`:
|
|
71
|
-
|
|
72
|
-
```rust
|
|
73
|
-
fn reuse_buffer(data: &[Vec<i32>]) {
|
|
74
|
-
let mut buffer = Vec::new();
|
|
75
|
-
|
|
76
|
-
for batch in data {
|
|
77
|
-
buffer.clear();
|
|
78
|
-
buffer.extend(batch.iter().filter(|&&x| x > 0).copied());
|
|
79
|
-
process(&buffer);
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
## Pattern: Transform and Reuse
|
|
85
|
-
|
|
86
|
-
```rust
|
|
87
|
-
fn transform_batches(batches: &[Vec<RawData>]) -> Vec<ProcessedData> {
|
|
88
|
-
let mut temp = Vec::new();
|
|
89
|
-
let mut all_results = Vec::new();
|
|
90
|
-
|
|
91
|
-
for batch in batches {
|
|
92
|
-
temp.clear();
|
|
93
|
-
batch.iter()
|
|
94
|
-
.map(ProcessedData::from)
|
|
95
|
-
.collect_into(&mut temp);
|
|
96
|
-
|
|
97
|
-
// Process temp, append to results
|
|
98
|
-
all_results.extend(temp.drain(..).filter(|p| p.is_valid()));
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
all_results
|
|
102
|
-
}
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
## Supported Collections
|
|
106
|
-
|
|
107
|
-
`collect_into()` works with any type implementing `Extend`:
|
|
108
|
-
|
|
109
|
-
```rust
|
|
110
|
-
use std::collections::{HashSet, HashMap, VecDeque};
|
|
111
|
-
|
|
112
|
-
let mut vec = Vec::new();
|
|
113
|
-
let mut set = HashSet::new();
|
|
114
|
-
let mut deque = VecDeque::new();
|
|
115
|
-
|
|
116
|
-
(0..10).collect_into(&mut vec);
|
|
117
|
-
(0..10).collect_into(&mut set);
|
|
118
|
-
(0..10).collect_into(&mut deque);
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
## Comparison
|
|
122
|
-
|
|
123
|
-
| Method | Allocation | Buffer Reuse |
|
|
124
|
-
|--------|------------|--------------|
|
|
125
|
-
| `.collect()` | New each time | No |
|
|
126
|
-
| `.collect_into(&mut buf)` | Reuses buffer | Yes |
|
|
127
|
-
| `buf.extend(iter)` | Reuses buffer | Yes |
|
|
128
|
-
|
|
129
|
-
## See Also
|
|
130
|
-
|
|
131
|
-
- [perf-drain-reuse](./perf-drain-reuse.md) - Drain for reuse
|
|
132
|
-
- [mem-reuse-collections](./mem-reuse-collections.md) - Collection reuse
|
|
133
|
-
- [perf-extend-batch](./perf-extend-batch.md) - Batch extensions
|
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
# perf-collect-once
|
|
2
|
-
|
|
3
|
-
> Don't collect intermediate iterators
|
|
4
|
-
|
|
5
|
-
## Why It Matters
|
|
6
|
-
|
|
7
|
-
Each `.collect()` allocates a new collection. Chaining multiple operations with intermediate collections wastes memory and CPU cycles. Keep iterator chains lazy and collect only once at the end.
|
|
8
|
-
|
|
9
|
-
## Bad
|
|
10
|
-
|
|
11
|
-
```rust
|
|
12
|
-
// Three allocations, three passes
|
|
13
|
-
fn process_users(users: Vec<User>) -> Vec<String> {
|
|
14
|
-
let active: Vec<_> = users.into_iter()
|
|
15
|
-
.filter(|u| u.is_active)
|
|
16
|
-
.collect();
|
|
17
|
-
|
|
18
|
-
let verified: Vec<_> = active.into_iter()
|
|
19
|
-
.filter(|u| u.is_verified)
|
|
20
|
-
.collect();
|
|
21
|
-
|
|
22
|
-
verified.into_iter()
|
|
23
|
-
.map(|u| u.name)
|
|
24
|
-
.collect()
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// Collecting to count
|
|
28
|
-
fn count_valid(items: &[Item]) -> usize {
|
|
29
|
-
items.iter()
|
|
30
|
-
.filter(|i| i.is_valid())
|
|
31
|
-
.collect::<Vec<_>>() // Unnecessary!
|
|
32
|
-
.len()
|
|
33
|
-
}
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
## Good
|
|
37
|
-
|
|
38
|
-
```rust
|
|
39
|
-
// One allocation, one pass
|
|
40
|
-
fn process_users(users: Vec<User>) -> Vec<String> {
|
|
41
|
-
users.into_iter()
|
|
42
|
-
.filter(|u| u.is_active)
|
|
43
|
-
.filter(|u| u.is_verified)
|
|
44
|
-
.map(|u| u.name)
|
|
45
|
-
.collect()
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// No allocation needed
|
|
49
|
-
fn count_valid(items: &[Item]) -> usize {
|
|
50
|
-
items.iter()
|
|
51
|
-
.filter(|i| i.is_valid())
|
|
52
|
-
.count()
|
|
53
|
-
}
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
## Pattern: Deferred Collection
|
|
57
|
-
|
|
58
|
-
```rust
|
|
59
|
-
// Create the iterator chain
|
|
60
|
-
fn prepare_data(raw: Vec<RawData>) -> impl Iterator<Item = ProcessedData> {
|
|
61
|
-
raw.into_iter()
|
|
62
|
-
.filter(|d| d.is_valid())
|
|
63
|
-
.map(ProcessedData::from)
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// Collect only when needed
|
|
67
|
-
let data: Vec<_> = prepare_data(input).collect();
|
|
68
|
-
|
|
69
|
-
// Or consume without collecting
|
|
70
|
-
prepare_data(input).for_each(|d| process(d));
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
## When Intermediate Collection Is Needed
|
|
74
|
-
|
|
75
|
-
```rust
|
|
76
|
-
// Need to iterate multiple times
|
|
77
|
-
let items: Vec<_> = data.iter()
|
|
78
|
-
.filter(|x| x.is_valid())
|
|
79
|
-
.collect();
|
|
80
|
-
|
|
81
|
-
let count = items.len();
|
|
82
|
-
let first = items.first();
|
|
83
|
-
for item in &items {
|
|
84
|
-
process(item);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// Need to sort (requires concrete collection)
|
|
88
|
-
let mut sorted: Vec<_> = data.iter()
|
|
89
|
-
.filter(|x| x.is_active)
|
|
90
|
-
.collect();
|
|
91
|
-
sorted.sort_by_key(|x| x.priority);
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
## Comparison
|
|
95
|
-
|
|
96
|
-
| Approach | Allocations | Passes | Memory |
|
|
97
|
-
|----------|-------------|--------|--------|
|
|
98
|
-
| Multiple `.collect()` | N | N | O(N × data) |
|
|
99
|
-
| Single chain + `.collect()` | 1 | 1 | O(data) |
|
|
100
|
-
| No `.collect()` (streaming) | 0 | 1 | O(1) |
|
|
101
|
-
|
|
102
|
-
## Pattern: Collect with Capacity
|
|
103
|
-
|
|
104
|
-
When you must collect, pre-allocate:
|
|
105
|
-
|
|
106
|
-
```rust
|
|
107
|
-
// With estimated capacity
|
|
108
|
-
let mut result = Vec::with_capacity(items.len());
|
|
109
|
-
result.extend(
|
|
110
|
-
items.iter()
|
|
111
|
-
.filter(|x| x.is_valid())
|
|
112
|
-
.map(|x| x.clone())
|
|
113
|
-
);
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
## See Also
|
|
117
|
-
|
|
118
|
-
- [perf-iter-lazy](./perf-iter-lazy.md) - Keep iterators lazy
|
|
119
|
-
- [mem-with-capacity](./mem-with-capacity.md) - Pre-allocate collections
|
|
120
|
-
- [anti-collect-intermediate](./anti-collect-intermediate.md) - Anti-pattern
|
|
@@ -1,137 +0,0 @@
|
|
|
1
|
-
# perf-drain-reuse
|
|
2
|
-
|
|
3
|
-
> Use drain to reuse allocations
|
|
4
|
-
|
|
5
|
-
## Why It Matters
|
|
6
|
-
|
|
7
|
-
`drain()` removes elements from a collection while keeping its allocated capacity. This allows reusing the same allocation across iterations, avoiding repeated allocate/deallocate cycles in loops.
|
|
8
|
-
|
|
9
|
-
## Bad
|
|
10
|
-
|
|
11
|
-
```rust
|
|
12
|
-
// Allocates new Vec every iteration
|
|
13
|
-
fn process_batches(data: Vec<Item>) {
|
|
14
|
-
let mut remaining = data;
|
|
15
|
-
|
|
16
|
-
while !remaining.is_empty() {
|
|
17
|
-
let batch: Vec<_> = remaining.drain(..100.min(remaining.len())).collect();
|
|
18
|
-
process_batch(batch);
|
|
19
|
-
// remaining keeps its capacity - good
|
|
20
|
-
// but batch allocates new every time - bad
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
// Clears and reallocates
|
|
25
|
-
fn reuse_buffer() {
|
|
26
|
-
for _ in 0..1000 {
|
|
27
|
-
let mut buffer = Vec::new(); // Allocates each iteration
|
|
28
|
-
fill_buffer(&mut buffer);
|
|
29
|
-
process(&buffer);
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
## Good
|
|
35
|
-
|
|
36
|
-
```rust
|
|
37
|
-
// Reuses allocation with drain
|
|
38
|
-
fn process_batches(mut data: Vec<Item>) {
|
|
39
|
-
let mut batch = Vec::with_capacity(100);
|
|
40
|
-
|
|
41
|
-
while !data.is_empty() {
|
|
42
|
-
batch.extend(data.drain(..100.min(data.len())));
|
|
43
|
-
process_batch(&batch);
|
|
44
|
-
batch.clear(); // Keeps capacity
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// Reuses buffer across iterations
|
|
49
|
-
fn reuse_buffer() {
|
|
50
|
-
let mut buffer = Vec::new();
|
|
51
|
-
|
|
52
|
-
for _ in 0..1000 {
|
|
53
|
-
buffer.clear(); // Keeps capacity
|
|
54
|
-
fill_buffer(&mut buffer);
|
|
55
|
-
process(&buffer);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
## Drain Methods
|
|
61
|
-
|
|
62
|
-
| Collection | Method | Behavior |
|
|
63
|
-
|------------|--------|----------|
|
|
64
|
-
| `Vec<T>` | `.drain(range)` | Remove range, shift remaining |
|
|
65
|
-
| `Vec<T>` | `.drain(..)` | Remove all (like clear) |
|
|
66
|
-
| `VecDeque<T>` | `.drain(range)` | Remove range |
|
|
67
|
-
| `String` | `.drain(range)` | Remove char range |
|
|
68
|
-
| `HashMap<K,V>` | `.drain()` | Remove all entries |
|
|
69
|
-
| `HashSet<T>` | `.drain()` | Remove all elements |
|
|
70
|
-
|
|
71
|
-
## Pattern: Batch Processing
|
|
72
|
-
|
|
73
|
-
```rust
|
|
74
|
-
fn process_in_chunks(mut items: Vec<Item>, chunk_size: usize) {
|
|
75
|
-
while !items.is_empty() {
|
|
76
|
-
let chunk: Vec<_> = items.drain(..chunk_size.min(items.len())).collect();
|
|
77
|
-
process_chunk(chunk);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
## Pattern: Transfer Between Collections
|
|
83
|
-
|
|
84
|
-
```rust
|
|
85
|
-
// Move all elements without reallocation
|
|
86
|
-
fn transfer_all(src: &mut Vec<Item>, dst: &mut Vec<Item>) {
|
|
87
|
-
dst.extend(src.drain(..));
|
|
88
|
-
// src is now empty but keeps capacity
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
// Move matching elements
|
|
92
|
-
fn transfer_matching(src: &mut Vec<Item>, dst: &mut Vec<Item>, predicate: impl Fn(&Item) -> bool) {
|
|
93
|
-
let matching: Vec<_> = src.drain(..).filter(predicate).collect();
|
|
94
|
-
dst.extend(matching);
|
|
95
|
-
}
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
## Pattern: HashMap Drain
|
|
99
|
-
|
|
100
|
-
```rust
|
|
101
|
-
use std::collections::HashMap;
|
|
102
|
-
|
|
103
|
-
fn process_and_clear(map: &mut HashMap<String, Value>) {
|
|
104
|
-
// Process all entries, clearing the map
|
|
105
|
-
for (key, value) in map.drain() {
|
|
106
|
-
process(key, value);
|
|
107
|
-
}
|
|
108
|
-
// map is now empty but keeps capacity
|
|
109
|
-
}
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
## drain vs clear vs take
|
|
113
|
-
|
|
114
|
-
| Operation | Elements | Capacity | Returns |
|
|
115
|
-
|-----------|----------|----------|---------|
|
|
116
|
-
| `.clear()` | Removed | Kept | Nothing |
|
|
117
|
-
| `.drain(..)` | Removed | Kept | Iterator |
|
|
118
|
-
| `std::mem::take()` | Moved out | Reset to 0 | Owned collection |
|
|
119
|
-
|
|
120
|
-
```rust
|
|
121
|
-
// clear: just empty
|
|
122
|
-
vec.clear();
|
|
123
|
-
|
|
124
|
-
// drain: empty and iterate
|
|
125
|
-
for item in vec.drain(..) {
|
|
126
|
-
process(item);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// take: swap with empty, get ownership
|
|
130
|
-
let old_vec = std::mem::take(&mut vec);
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
## See Also
|
|
134
|
-
|
|
135
|
-
- [mem-reuse-collections](./mem-reuse-collections.md) - Reusing collections
|
|
136
|
-
- [perf-extend-batch](./perf-extend-batch.md) - Batch insertions
|
|
137
|
-
- [mem-with-capacity](./mem-with-capacity.md) - Pre-allocation
|
|
@@ -1,134 +0,0 @@
|
|
|
1
|
-
# perf-entry-api
|
|
2
|
-
|
|
3
|
-
> Use entry API for map insert-or-update
|
|
4
|
-
|
|
5
|
-
## Why It Matters
|
|
6
|
-
|
|
7
|
-
The entry API performs a single lookup for insert-or-update operations. Without it, you lookup twice: once to check existence, once to insert. For `HashMap` and `BTreeMap`, the entry API is both faster and more idiomatic.
|
|
8
|
-
|
|
9
|
-
## Bad
|
|
10
|
-
|
|
11
|
-
```rust
|
|
12
|
-
use std::collections::HashMap;
|
|
13
|
-
|
|
14
|
-
// Double lookup: contains_key + insert
|
|
15
|
-
fn increment(map: &mut HashMap<String, u32>, key: String) {
|
|
16
|
-
if map.contains_key(&key) {
|
|
17
|
-
*map.get_mut(&key).unwrap() += 1;
|
|
18
|
-
} else {
|
|
19
|
-
map.insert(key, 1);
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
// Double lookup with get + insert
|
|
24
|
-
fn get_or_insert(map: &mut HashMap<String, Vec<i32>>, key: String) -> &mut Vec<i32> {
|
|
25
|
-
if !map.contains_key(&key) {
|
|
26
|
-
map.insert(key.clone(), Vec::new());
|
|
27
|
-
}
|
|
28
|
-
map.get_mut(&key).unwrap()
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// Triple lookup pattern
|
|
32
|
-
fn update_or_default(map: &mut HashMap<String, Config>, key: &str, value: i32) {
|
|
33
|
-
match map.get(key) {
|
|
34
|
-
Some(config) => {
|
|
35
|
-
let mut new_config = config.clone();
|
|
36
|
-
new_config.value = value;
|
|
37
|
-
map.insert(key.to_string(), new_config);
|
|
38
|
-
}
|
|
39
|
-
None => {
|
|
40
|
-
map.insert(key.to_string(), Config::default());
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
## Good
|
|
47
|
-
|
|
48
|
-
```rust
|
|
49
|
-
use std::collections::HashMap;
|
|
50
|
-
use std::collections::hash_map::Entry;
|
|
51
|
-
|
|
52
|
-
// Single lookup with entry
|
|
53
|
-
fn increment(map: &mut HashMap<String, u32>, key: String) {
|
|
54
|
-
*map.entry(key).or_insert(0) += 1;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// Single lookup, returns mutable reference
|
|
58
|
-
fn get_or_insert(map: &mut HashMap<String, Vec<i32>>, key: String) -> &mut Vec<i32> {
|
|
59
|
-
map.entry(key).or_insert_with(Vec::new)
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// Single lookup with and_modify
|
|
63
|
-
fn update_or_default(map: &mut HashMap<String, Config>, key: String, value: i32) {
|
|
64
|
-
map.entry(key)
|
|
65
|
-
.and_modify(|config| config.value = value)
|
|
66
|
-
.or_insert_with(Config::default);
|
|
67
|
-
}
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
## Entry API Methods
|
|
71
|
-
|
|
72
|
-
| Method | Behavior |
|
|
73
|
-
|--------|----------|
|
|
74
|
-
| `.or_insert(val)` | Insert `val` if empty |
|
|
75
|
-
| `.or_insert_with(f)` | Insert `f()` if empty (lazy) |
|
|
76
|
-
| `.or_default()` | Insert `Default::default()` if empty |
|
|
77
|
-
| `.and_modify(f)` | Apply `f` if occupied |
|
|
78
|
-
| `.or_insert_with_key(f)` | Insert `f(&key)` if empty |
|
|
79
|
-
|
|
80
|
-
## Pattern: Count Occurrences
|
|
81
|
-
|
|
82
|
-
```rust
|
|
83
|
-
fn word_count(text: &str) -> HashMap<&str, usize> {
|
|
84
|
-
let mut counts = HashMap::new();
|
|
85
|
-
for word in text.split_whitespace() {
|
|
86
|
-
*counts.entry(word).or_insert(0) += 1;
|
|
87
|
-
}
|
|
88
|
-
counts
|
|
89
|
-
}
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
## Pattern: Group By
|
|
93
|
-
|
|
94
|
-
```rust
|
|
95
|
-
fn group_by_category(items: Vec<Item>) -> HashMap<Category, Vec<Item>> {
|
|
96
|
-
let mut groups: HashMap<Category, Vec<Item>> = HashMap::new();
|
|
97
|
-
for item in items {
|
|
98
|
-
groups.entry(item.category.clone())
|
|
99
|
-
.or_default()
|
|
100
|
-
.push(item);
|
|
101
|
-
}
|
|
102
|
-
groups
|
|
103
|
-
}
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
## Pattern: Complex Entry Logic
|
|
107
|
-
|
|
108
|
-
```rust
|
|
109
|
-
match map.entry(key) {
|
|
110
|
-
Entry::Occupied(mut entry) => {
|
|
111
|
-
let value = entry.get_mut();
|
|
112
|
-
if should_update(value) {
|
|
113
|
-
*value = new_value;
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
Entry::Vacant(entry) => {
|
|
117
|
-
entry.insert(default_value);
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
## Performance
|
|
123
|
-
|
|
124
|
-
| Pattern | Lookups | Hash Computations |
|
|
125
|
-
|---------|---------|-------------------|
|
|
126
|
-
| `contains_key` + `insert` | 2 | 2 |
|
|
127
|
-
| `get` + `insert` | 2 | 2 |
|
|
128
|
-
| `entry().or_insert()` | 1 | 1 |
|
|
129
|
-
|
|
130
|
-
## See Also
|
|
131
|
-
|
|
132
|
-
- [perf-extend-batch](./perf-extend-batch.md) - Batch insertions
|
|
133
|
-
- [mem-with-capacity](./mem-with-capacity.md) - Pre-allocate maps
|
|
134
|
-
- [perf-drain-reuse](./perf-drain-reuse.md) - Reuse map allocations
|
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
# perf-extend-batch
|
|
2
|
-
|
|
3
|
-
> Use extend for batch insertions
|
|
4
|
-
|
|
5
|
-
## Why It Matters
|
|
6
|
-
|
|
7
|
-
`extend()` can pre-allocate capacity for the incoming elements and insert them in a single operation. Individual `push()` calls may trigger multiple reallocations as the collection grows. For adding multiple elements, `extend()` is both faster and clearer.
|
|
8
|
-
|
|
9
|
-
## Bad
|
|
10
|
-
|
|
11
|
-
```rust
|
|
12
|
-
// Multiple potential reallocations
|
|
13
|
-
fn collect_results(sources: Vec<Source>) -> Vec<Result> {
|
|
14
|
-
let mut results = Vec::new();
|
|
15
|
-
|
|
16
|
-
for source in sources {
|
|
17
|
-
for result in source.get_results() {
|
|
18
|
-
results.push(result); // May reallocate
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
results
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
// Loop with push for known data
|
|
25
|
-
fn build_list() -> Vec<i32> {
|
|
26
|
-
let mut list = Vec::new();
|
|
27
|
-
for i in 0..1000 {
|
|
28
|
-
list.push(i); // Many reallocations
|
|
29
|
-
}
|
|
30
|
-
list
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// Appending another collection
|
|
34
|
-
fn combine(mut a: Vec<i32>, b: Vec<i32>) -> Vec<i32> {
|
|
35
|
-
for item in b {
|
|
36
|
-
a.push(item);
|
|
37
|
-
}
|
|
38
|
-
a
|
|
39
|
-
}
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
## Good
|
|
43
|
-
|
|
44
|
-
```rust
|
|
45
|
-
// Single extend with size hint
|
|
46
|
-
fn collect_results(sources: Vec<Source>) -> Vec<Result> {
|
|
47
|
-
let mut results = Vec::new();
|
|
48
|
-
|
|
49
|
-
for source in sources {
|
|
50
|
-
results.extend(source.get_results());
|
|
51
|
-
}
|
|
52
|
-
results
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// Direct collection from iterator
|
|
56
|
-
fn build_list() -> Vec<i32> {
|
|
57
|
-
(0..1000).collect()
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// Extend for combining
|
|
61
|
-
fn combine(mut a: Vec<i32>, b: Vec<i32>) -> Vec<i32> {
|
|
62
|
-
a.extend(b);
|
|
63
|
-
a
|
|
64
|
-
}
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
## Extend with Capacity
|
|
68
|
-
|
|
69
|
-
For best performance, combine with `reserve()`:
|
|
70
|
-
|
|
71
|
-
```rust
|
|
72
|
-
fn merge_all(chunks: Vec<Vec<Item>>) -> Vec<Item> {
|
|
73
|
-
// Calculate total size
|
|
74
|
-
let total: usize = chunks.iter().map(|c| c.len()).sum();
|
|
75
|
-
|
|
76
|
-
let mut result = Vec::with_capacity(total);
|
|
77
|
-
for chunk in chunks {
|
|
78
|
-
result.extend(chunk);
|
|
79
|
-
}
|
|
80
|
-
result
|
|
81
|
-
}
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
## Extend Methods
|
|
85
|
-
|
|
86
|
-
| Method | Description |
|
|
87
|
-
|--------|-------------|
|
|
88
|
-
| `.extend(iter)` | Add all elements from iterator |
|
|
89
|
-
| `.extend_from_slice(&[T])` | Add from slice (for `Copy` types) |
|
|
90
|
-
| `.append(&mut Vec)` | Move all from another Vec |
|
|
91
|
-
|
|
92
|
-
## Pattern: Building Strings
|
|
93
|
-
|
|
94
|
-
```rust
|
|
95
|
-
// Bad: multiple allocations
|
|
96
|
-
fn build_message(parts: &[&str]) -> String {
|
|
97
|
-
let mut result = String::new();
|
|
98
|
-
for part in parts {
|
|
99
|
-
result.push_str(part); // May reallocate
|
|
100
|
-
}
|
|
101
|
-
result
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// Good: extend with known parts
|
|
105
|
-
fn build_message(parts: &[&str]) -> String {
|
|
106
|
-
let total_len: usize = parts.iter().map(|s| s.len()).sum();
|
|
107
|
-
let mut result = String::with_capacity(total_len);
|
|
108
|
-
for part in parts {
|
|
109
|
-
result.push_str(part);
|
|
110
|
-
}
|
|
111
|
-
result
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
// Better: collect/join
|
|
115
|
-
fn build_message(parts: &[&str]) -> String {
|
|
116
|
-
parts.concat() // or parts.join("")
|
|
117
|
-
}
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
## HashMap/HashSet Extend
|
|
121
|
-
|
|
122
|
-
```rust
|
|
123
|
-
use std::collections::HashMap;
|
|
124
|
-
|
|
125
|
-
// Extend from iterator of tuples
|
|
126
|
-
fn merge_maps(mut base: HashMap<String, i32>, other: HashMap<String, i32>) -> HashMap<String, i32> {
|
|
127
|
-
base.extend(other); // Moves entries from other
|
|
128
|
-
base
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// Extend from iterator
|
|
132
|
-
let mut set = HashSet::new();
|
|
133
|
-
set.extend(items.iter().map(|i| i.id));
|
|
134
|
-
```
|
|
135
|
-
|
|
136
|
-
## Performance
|
|
137
|
-
|
|
138
|
-
| Operation | Allocations | Complexity |
|
|
139
|
-
|-----------|-------------|------------|
|
|
140
|
-
| N × `push()` | O(log N) | O(N) amortized |
|
|
141
|
-
| `extend(iter)` | O(1)* | O(N) |
|
|
142
|
-
| `with_capacity` + `extend` | 1 | O(N) |
|
|
143
|
-
|
|
144
|
-
*When iterator provides accurate `size_hint()`
|
|
145
|
-
|
|
146
|
-
## See Also
|
|
147
|
-
|
|
148
|
-
- [mem-with-capacity](./mem-with-capacity.md) - Pre-allocation
|
|
149
|
-
- [perf-drain-reuse](./perf-drain-reuse.md) - Reusing allocations
|
|
150
|
-
- [mem-reuse-collections](./mem-reuse-collections.md) - Collection reuse
|