agy-superpowers 5.1.4 → 5.1.6

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.
Files changed (185) hide show
  1. package/package.json +1 -1
  2. package/template/agent/rules/debug-confirmation-policy.md +34 -0
  3. package/template/agent/rules/language-matching.md +32 -0
  4. package/template/agent/skills/rust-developer/SKILL.md +281 -0
  5. package/template/agent/skills/rust-developer/references/rust-rules/_sections.md +231 -0
  6. package/template/agent/skills/rust-developer/references/rust-rules/anti-clone-excessive.md +124 -0
  7. package/template/agent/skills/rust-developer/references/rust-rules/anti-collect-intermediate.md +131 -0
  8. package/template/agent/skills/rust-developer/references/rust-rules/anti-empty-catch.md +132 -0
  9. package/template/agent/skills/rust-developer/references/rust-rules/anti-expect-lazy.md +95 -0
  10. package/template/agent/skills/rust-developer/references/rust-rules/anti-format-hot-path.md +141 -0
  11. package/template/agent/skills/rust-developer/references/rust-rules/anti-index-over-iter.md +125 -0
  12. package/template/agent/skills/rust-developer/references/rust-rules/anti-lock-across-await.md +127 -0
  13. package/template/agent/skills/rust-developer/references/rust-rules/anti-over-abstraction.md +120 -0
  14. package/template/agent/skills/rust-developer/references/rust-rules/anti-panic-expected.md +131 -0
  15. package/template/agent/skills/rust-developer/references/rust-rules/anti-premature-optimize.md +156 -0
  16. package/template/agent/skills/rust-developer/references/rust-rules/anti-string-for-str.md +122 -0
  17. package/template/agent/skills/rust-developer/references/rust-rules/anti-stringly-typed.md +167 -0
  18. package/template/agent/skills/rust-developer/references/rust-rules/anti-type-erasure.md +134 -0
  19. package/template/agent/skills/rust-developer/references/rust-rules/anti-unwrap-abuse.md +143 -0
  20. package/template/agent/skills/rust-developer/references/rust-rules/anti-vec-for-slice.md +121 -0
  21. package/template/agent/skills/rust-developer/references/rust-rules/api-builder-must-use.md +143 -0
  22. package/template/agent/skills/rust-developer/references/rust-rules/api-builder-pattern.md +187 -0
  23. package/template/agent/skills/rust-developer/references/rust-rules/api-common-traits.md +165 -0
  24. package/template/agent/skills/rust-developer/references/rust-rules/api-default-impl.md +177 -0
  25. package/template/agent/skills/rust-developer/references/rust-rules/api-extension-trait.md +163 -0
  26. package/template/agent/skills/rust-developer/references/rust-rules/api-from-not-into.md +146 -0
  27. package/template/agent/skills/rust-developer/references/rust-rules/api-impl-asref.md +142 -0
  28. package/template/agent/skills/rust-developer/references/rust-rules/api-impl-into.md +160 -0
  29. package/template/agent/skills/rust-developer/references/rust-rules/api-must-use.md +125 -0
  30. package/template/agent/skills/rust-developer/references/rust-rules/api-newtype-safety.md +162 -0
  31. package/template/agent/skills/rust-developer/references/rust-rules/api-non-exhaustive.md +177 -0
  32. package/template/agent/skills/rust-developer/references/rust-rules/api-parse-dont-validate.md +184 -0
  33. package/template/agent/skills/rust-developer/references/rust-rules/api-sealed-trait.md +168 -0
  34. package/template/agent/skills/rust-developer/references/rust-rules/api-serde-optional.md +182 -0
  35. package/template/agent/skills/rust-developer/references/rust-rules/api-typestate.md +199 -0
  36. package/template/agent/skills/rust-developer/references/rust-rules/async-bounded-channel.md +175 -0
  37. package/template/agent/skills/rust-developer/references/rust-rules/async-broadcast-pubsub.md +185 -0
  38. package/template/agent/skills/rust-developer/references/rust-rules/async-cancellation-token.md +203 -0
  39. package/template/agent/skills/rust-developer/references/rust-rules/async-clone-before-await.md +171 -0
  40. package/template/agent/skills/rust-developer/references/rust-rules/async-join-parallel.md +158 -0
  41. package/template/agent/skills/rust-developer/references/rust-rules/async-joinset-structured.md +195 -0
  42. package/template/agent/skills/rust-developer/references/rust-rules/async-mpsc-queue.md +171 -0
  43. package/template/agent/skills/rust-developer/references/rust-rules/async-no-lock-await.md +156 -0
  44. package/template/agent/skills/rust-developer/references/rust-rules/async-oneshot-response.md +191 -0
  45. package/template/agent/skills/rust-developer/references/rust-rules/async-select-racing.md +198 -0
  46. package/template/agent/skills/rust-developer/references/rust-rules/async-spawn-blocking.md +154 -0
  47. package/template/agent/skills/rust-developer/references/rust-rules/async-tokio-fs.md +167 -0
  48. package/template/agent/skills/rust-developer/references/rust-rules/async-tokio-runtime.md +169 -0
  49. package/template/agent/skills/rust-developer/references/rust-rules/async-try-join.md +172 -0
  50. package/template/agent/skills/rust-developer/references/rust-rules/async-watch-latest.md +189 -0
  51. package/template/agent/skills/rust-developer/references/rust-rules/doc-all-public.md +113 -0
  52. package/template/agent/skills/rust-developer/references/rust-rules/doc-cargo-metadata.md +147 -0
  53. package/template/agent/skills/rust-developer/references/rust-rules/doc-errors-section.md +122 -0
  54. package/template/agent/skills/rust-developer/references/rust-rules/doc-examples-section.md +161 -0
  55. package/template/agent/skills/rust-developer/references/rust-rules/doc-hidden-setup.md +149 -0
  56. package/template/agent/skills/rust-developer/references/rust-rules/doc-intra-links.md +138 -0
  57. package/template/agent/skills/rust-developer/references/rust-rules/doc-link-types.md +169 -0
  58. package/template/agent/skills/rust-developer/references/rust-rules/doc-module-inner.md +116 -0
  59. package/template/agent/skills/rust-developer/references/rust-rules/doc-panics-section.md +128 -0
  60. package/template/agent/skills/rust-developer/references/rust-rules/doc-question-mark.md +136 -0
  61. package/template/agent/skills/rust-developer/references/rust-rules/doc-safety-section.md +131 -0
  62. package/template/agent/skills/rust-developer/references/rust-rules/err-anyhow-app.md +179 -0
  63. package/template/agent/skills/rust-developer/references/rust-rules/err-context-chain.md +144 -0
  64. package/template/agent/skills/rust-developer/references/rust-rules/err-custom-type.md +152 -0
  65. package/template/agent/skills/rust-developer/references/rust-rules/err-doc-errors.md +145 -0
  66. package/template/agent/skills/rust-developer/references/rust-rules/err-expect-bugs-only.md +133 -0
  67. package/template/agent/skills/rust-developer/references/rust-rules/err-from-impl.md +152 -0
  68. package/template/agent/skills/rust-developer/references/rust-rules/err-lowercase-msg.md +124 -0
  69. package/template/agent/skills/rust-developer/references/rust-rules/err-no-unwrap-prod.md +115 -0
  70. package/template/agent/skills/rust-developer/references/rust-rules/err-question-mark.md +151 -0
  71. package/template/agent/skills/rust-developer/references/rust-rules/err-result-over-panic.md +130 -0
  72. package/template/agent/skills/rust-developer/references/rust-rules/err-source-chain.md +155 -0
  73. package/template/agent/skills/rust-developer/references/rust-rules/err-thiserror-lib.md +171 -0
  74. package/template/agent/skills/rust-developer/references/rust-rules/lint-cargo-metadata.md +138 -0
  75. package/template/agent/skills/rust-developer/references/rust-rules/lint-deny-correctness.md +107 -0
  76. package/template/agent/skills/rust-developer/references/rust-rules/lint-missing-docs.md +154 -0
  77. package/template/agent/skills/rust-developer/references/rust-rules/lint-pedantic-selective.md +118 -0
  78. package/template/agent/skills/rust-developer/references/rust-rules/lint-rustfmt-check.md +157 -0
  79. package/template/agent/skills/rust-developer/references/rust-rules/lint-unsafe-doc.md +133 -0
  80. package/template/agent/skills/rust-developer/references/rust-rules/lint-warn-complexity.md +131 -0
  81. package/template/agent/skills/rust-developer/references/rust-rules/lint-warn-perf.md +136 -0
  82. package/template/agent/skills/rust-developer/references/rust-rules/lint-warn-style.md +135 -0
  83. package/template/agent/skills/rust-developer/references/rust-rules/lint-warn-suspicious.md +122 -0
  84. package/template/agent/skills/rust-developer/references/rust-rules/lint-workspace-lints.md +172 -0
  85. package/template/agent/skills/rust-developer/references/rust-rules/mem-arena-allocator.md +168 -0
  86. package/template/agent/skills/rust-developer/references/rust-rules/mem-arrayvec.md +142 -0
  87. package/template/agent/skills/rust-developer/references/rust-rules/mem-assert-type-size.md +168 -0
  88. package/template/agent/skills/rust-developer/references/rust-rules/mem-avoid-format.md +147 -0
  89. package/template/agent/skills/rust-developer/references/rust-rules/mem-box-large-variant.md +158 -0
  90. package/template/agent/skills/rust-developer/references/rust-rules/mem-boxed-slice.md +139 -0
  91. package/template/agent/skills/rust-developer/references/rust-rules/mem-clone-from.md +147 -0
  92. package/template/agent/skills/rust-developer/references/rust-rules/mem-compact-string.md +149 -0
  93. package/template/agent/skills/rust-developer/references/rust-rules/mem-reuse-collections.md +174 -0
  94. package/template/agent/skills/rust-developer/references/rust-rules/mem-smaller-integers.md +159 -0
  95. package/template/agent/skills/rust-developer/references/rust-rules/mem-smallvec.md +138 -0
  96. package/template/agent/skills/rust-developer/references/rust-rules/mem-thinvec.md +142 -0
  97. package/template/agent/skills/rust-developer/references/rust-rules/mem-with-capacity.md +156 -0
  98. package/template/agent/skills/rust-developer/references/rust-rules/mem-write-over-format.md +172 -0
  99. package/template/agent/skills/rust-developer/references/rust-rules/mem-zero-copy.md +164 -0
  100. package/template/agent/skills/rust-developer/references/rust-rules/name-acronym-word.md +99 -0
  101. package/template/agent/skills/rust-developer/references/rust-rules/name-as-free.md +104 -0
  102. package/template/agent/skills/rust-developer/references/rust-rules/name-consts-screaming.md +94 -0
  103. package/template/agent/skills/rust-developer/references/rust-rules/name-crate-no-rs.md +78 -0
  104. package/template/agent/skills/rust-developer/references/rust-rules/name-funcs-snake.md +76 -0
  105. package/template/agent/skills/rust-developer/references/rust-rules/name-into-ownership.md +123 -0
  106. package/template/agent/skills/rust-developer/references/rust-rules/name-is-has-bool.md +127 -0
  107. package/template/agent/skills/rust-developer/references/rust-rules/name-iter-convention.md +129 -0
  108. package/template/agent/skills/rust-developer/references/rust-rules/name-iter-method.md +131 -0
  109. package/template/agent/skills/rust-developer/references/rust-rules/name-iter-type-match.md +142 -0
  110. package/template/agent/skills/rust-developer/references/rust-rules/name-lifetime-short.md +86 -0
  111. package/template/agent/skills/rust-developer/references/rust-rules/name-no-get-prefix.md +154 -0
  112. package/template/agent/skills/rust-developer/references/rust-rules/name-to-expensive.md +118 -0
  113. package/template/agent/skills/rust-developer/references/rust-rules/name-type-param-single.md +92 -0
  114. package/template/agent/skills/rust-developer/references/rust-rules/name-types-camel.md +65 -0
  115. package/template/agent/skills/rust-developer/references/rust-rules/name-variants-camel.md +101 -0
  116. package/template/agent/skills/rust-developer/references/rust-rules/opt-bounds-check.md +161 -0
  117. package/template/agent/skills/rust-developer/references/rust-rules/opt-cache-friendly.md +187 -0
  118. package/template/agent/skills/rust-developer/references/rust-rules/opt-codegen-units.md +142 -0
  119. package/template/agent/skills/rust-developer/references/rust-rules/opt-cold-unlikely.md +152 -0
  120. package/template/agent/skills/rust-developer/references/rust-rules/opt-inline-always-rare.md +141 -0
  121. package/template/agent/skills/rust-developer/references/rust-rules/opt-inline-never-cold.md +181 -0
  122. package/template/agent/skills/rust-developer/references/rust-rules/opt-inline-small.md +160 -0
  123. package/template/agent/skills/rust-developer/references/rust-rules/opt-likely-hint.md +171 -0
  124. package/template/agent/skills/rust-developer/references/rust-rules/opt-lto-release.md +130 -0
  125. package/template/agent/skills/rust-developer/references/rust-rules/opt-pgo-profile.md +167 -0
  126. package/template/agent/skills/rust-developer/references/rust-rules/opt-simd-portable.md +144 -0
  127. package/template/agent/skills/rust-developer/references/rust-rules/opt-target-cpu.md +154 -0
  128. package/template/agent/skills/rust-developer/references/rust-rules/own-arc-shared.md +141 -0
  129. package/template/agent/skills/rust-developer/references/rust-rules/own-borrow-over-clone.md +95 -0
  130. package/template/agent/skills/rust-developer/references/rust-rules/own-clone-explicit.md +135 -0
  131. package/template/agent/skills/rust-developer/references/rust-rules/own-copy-small.md +124 -0
  132. package/template/agent/skills/rust-developer/references/rust-rules/own-cow-conditional.md +135 -0
  133. package/template/agent/skills/rust-developer/references/rust-rules/own-lifetime-elision.md +134 -0
  134. package/template/agent/skills/rust-developer/references/rust-rules/own-move-large.md +134 -0
  135. package/template/agent/skills/rust-developer/references/rust-rules/own-mutex-interior.md +105 -0
  136. package/template/agent/skills/rust-developer/references/rust-rules/own-rc-single-thread.md +65 -0
  137. package/template/agent/skills/rust-developer/references/rust-rules/own-refcell-interior.md +97 -0
  138. package/template/agent/skills/rust-developer/references/rust-rules/own-rwlock-readers.md +122 -0
  139. package/template/agent/skills/rust-developer/references/rust-rules/own-slice-over-vec.md +119 -0
  140. package/template/agent/skills/rust-developer/references/rust-rules/perf-black-box-bench.md +153 -0
  141. package/template/agent/skills/rust-developer/references/rust-rules/perf-chain-avoid.md +136 -0
  142. package/template/agent/skills/rust-developer/references/rust-rules/perf-collect-into.md +133 -0
  143. package/template/agent/skills/rust-developer/references/rust-rules/perf-collect-once.md +120 -0
  144. package/template/agent/skills/rust-developer/references/rust-rules/perf-drain-reuse.md +137 -0
  145. package/template/agent/skills/rust-developer/references/rust-rules/perf-entry-api.md +134 -0
  146. package/template/agent/skills/rust-developer/references/rust-rules/perf-extend-batch.md +150 -0
  147. package/template/agent/skills/rust-developer/references/rust-rules/perf-iter-lazy.md +123 -0
  148. package/template/agent/skills/rust-developer/references/rust-rules/perf-iter-over-index.md +113 -0
  149. package/template/agent/skills/rust-developer/references/rust-rules/perf-profile-first.md +175 -0
  150. package/template/agent/skills/rust-developer/references/rust-rules/perf-release-profile.md +149 -0
  151. package/template/agent/skills/rust-developer/references/rust-rules/proj-bin-dir.md +142 -0
  152. package/template/agent/skills/rust-developer/references/rust-rules/proj-flat-small.md +133 -0
  153. package/template/agent/skills/rust-developer/references/rust-rules/proj-lib-main-split.md +148 -0
  154. package/template/agent/skills/rust-developer/references/rust-rules/proj-mod-by-feature.md +130 -0
  155. package/template/agent/skills/rust-developer/references/rust-rules/proj-mod-rs-dir.md +120 -0
  156. package/template/agent/skills/rust-developer/references/rust-rules/proj-prelude-module.md +155 -0
  157. package/template/agent/skills/rust-developer/references/rust-rules/proj-pub-crate-internal.md +139 -0
  158. package/template/agent/skills/rust-developer/references/rust-rules/proj-pub-super-parent.md +135 -0
  159. package/template/agent/skills/rust-developer/references/rust-rules/proj-pub-use-reexport.md +162 -0
  160. package/template/agent/skills/rust-developer/references/rust-rules/proj-workspace-deps.md +186 -0
  161. package/template/agent/skills/rust-developer/references/rust-rules/proj-workspace-large.md +162 -0
  162. package/template/agent/skills/rust-developer/references/rust-rules/test-arrange-act-assert.md +160 -0
  163. package/template/agent/skills/rust-developer/references/rust-rules/test-cfg-test-module.md +151 -0
  164. package/template/agent/skills/rust-developer/references/rust-rules/test-criterion-bench.md +171 -0
  165. package/template/agent/skills/rust-developer/references/rust-rules/test-descriptive-names.md +142 -0
  166. package/template/agent/skills/rust-developer/references/rust-rules/test-doctest-examples.md +168 -0
  167. package/template/agent/skills/rust-developer/references/rust-rules/test-fixture-raii.md +151 -0
  168. package/template/agent/skills/rust-developer/references/rust-rules/test-integration-dir.md +144 -0
  169. package/template/agent/skills/rust-developer/references/rust-rules/test-mock-traits.md +189 -0
  170. package/template/agent/skills/rust-developer/references/rust-rules/test-mockall-mocking.md +226 -0
  171. package/template/agent/skills/rust-developer/references/rust-rules/test-proptest-properties.md +161 -0
  172. package/template/agent/skills/rust-developer/references/rust-rules/test-should-panic.md +130 -0
  173. package/template/agent/skills/rust-developer/references/rust-rules/test-tokio-async.md +154 -0
  174. package/template/agent/skills/rust-developer/references/rust-rules/test-use-super.md +127 -0
  175. package/template/agent/skills/rust-developer/references/rust-rules/type-enum-states.md +154 -0
  176. package/template/agent/skills/rust-developer/references/rust-rules/type-generic-bounds.md +142 -0
  177. package/template/agent/skills/rust-developer/references/rust-rules/type-never-diverge.md +146 -0
  178. package/template/agent/skills/rust-developer/references/rust-rules/type-newtype-ids.md +160 -0
  179. package/template/agent/skills/rust-developer/references/rust-rules/type-newtype-validated.md +159 -0
  180. package/template/agent/skills/rust-developer/references/rust-rules/type-no-stringly.md +144 -0
  181. package/template/agent/skills/rust-developer/references/rust-rules/type-option-nullable.md +137 -0
  182. package/template/agent/skills/rust-developer/references/rust-rules/type-phantom-marker.md +188 -0
  183. package/template/agent/skills/rust-developer/references/rust-rules/type-repr-transparent.md +143 -0
  184. package/template/agent/skills/rust-developer/references/rust-rules/type-result-fallible.md +131 -0
  185. package/template/agent/skills/systematic-debugging/SKILL.md +17 -0
@@ -0,0 +1,136 @@
1
+ # perf-chain-avoid
2
+
3
+ > Avoid chain in hot loops
4
+
5
+ ## Why It Matters
6
+
7
+ `Iterator::chain()` adds overhead for checking which iterator is active on every `.next()` call. In hot loops, this branch prediction overhead can impact performance. For performance-critical code, prefer single iterators or pre-combined collections.
8
+
9
+ ## Bad
10
+
11
+ ```rust
12
+ // Chain in hot inner loop
13
+ fn process_hot_path(a: &[i32], b: &[i32]) -> i64 {
14
+ let mut sum = 0i64;
15
+
16
+ // Called millions of times
17
+ for _ in 0..1_000_000 {
18
+ for x in a.iter().chain(b.iter()) { // Branch every iteration
19
+ sum += *x as i64;
20
+ }
21
+ }
22
+ sum
23
+ }
24
+
25
+ // Chaining multiple small slices in tight loop
26
+ fn combine_results(parts: &[&[u8]]) -> Vec<u8> {
27
+ let mut result = Vec::new();
28
+ for part in parts {
29
+ for byte in std::iter::once(&0u8).chain(part.iter()) {
30
+ result.push(*byte);
31
+ }
32
+ }
33
+ result
34
+ }
35
+ ```
36
+
37
+ ## Good
38
+
39
+ ```rust
40
+ // Separate loops - branch-free inner loops
41
+ fn process_hot_path(a: &[i32], b: &[i32]) -> i64 {
42
+ let mut sum = 0i64;
43
+
44
+ for _ in 0..1_000_000 {
45
+ for x in a {
46
+ sum += *x as i64;
47
+ }
48
+ for x in b {
49
+ sum += *x as i64;
50
+ }
51
+ }
52
+ sum
53
+ }
54
+
55
+ // Pre-combine outside hot loop
56
+ fn combine_results(parts: &[&[u8]]) -> Vec<u8> {
57
+ let mut result = Vec::new();
58
+ for part in parts {
59
+ result.push(0u8);
60
+ result.extend_from_slice(part);
61
+ }
62
+ result
63
+ }
64
+ ```
65
+
66
+ ## When Chain Is Fine
67
+
68
+ Chain is perfectly acceptable when:
69
+
70
+ ```rust
71
+ // One-time iteration, not in hot path
72
+ fn collect_all(a: Vec<i32>, b: Vec<i32>) -> Vec<i32> {
73
+ a.into_iter().chain(b).collect()
74
+ }
75
+
76
+ // Lazy evaluation with short-circuit
77
+ fn find_in_either(a: &[Item], b: &[Item], target: i32) -> Option<&Item> {
78
+ a.iter().chain(b.iter()).find(|x| x.id == target)
79
+ }
80
+
81
+ // Small number of elements
82
+ fn get_prefixes() -> impl Iterator<Item = &'static str> {
83
+ ["Mr.", "Mrs.", "Dr."].iter().copied()
84
+ .chain(["Prof."].iter().copied())
85
+ }
86
+ ```
87
+
88
+ ## Alternative Patterns
89
+
90
+ ### Pre-allocate and Extend
91
+
92
+ ```rust
93
+ fn merge_slices(slices: &[&[i32]]) -> Vec<i32> {
94
+ let total: usize = slices.iter().map(|s| s.len()).sum();
95
+ let mut result = Vec::with_capacity(total);
96
+ for slice in slices {
97
+ result.extend_from_slice(slice);
98
+ }
99
+ result
100
+ }
101
+ ```
102
+
103
+ ### Use append for Vecs
104
+
105
+ ```rust
106
+ fn combine_vecs(mut a: Vec<i32>, mut b: Vec<i32>) -> Vec<i32> {
107
+ a.append(&mut b); // Moves elements, no reallocation if a has capacity
108
+ a
109
+ }
110
+ ```
111
+
112
+ ### Flatten Instead of Chain
113
+
114
+ ```rust
115
+ // Instead of: a.iter().chain(b.iter()).chain(c.iter())
116
+ let all = [a, b, c];
117
+ for item in all.iter().flat_map(|slice| slice.iter()) {
118
+ process(item);
119
+ }
120
+ ```
121
+
122
+ ## Performance Impact
123
+
124
+ | Pattern | Per-Item Overhead |
125
+ |---------|-------------------|
126
+ | Single iterator | None |
127
+ | `chain(a, b)` | 1 branch per item |
128
+ | `chain(a, b, c)` | 2 branches per item |
129
+ | Nested chains | Compounds |
130
+ | Separate loops | None (but code duplication) |
131
+
132
+ ## See Also
133
+
134
+ - [perf-iter-over-index](./perf-iter-over-index.md) - Prefer iterators
135
+ - [perf-extend-batch](./perf-extend-batch.md) - Batch insertions
136
+ - [opt-cache-friendly](./opt-cache-friendly.md) - Cache-friendly patterns
@@ -0,0 +1,133 @@
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
@@ -0,0 +1,120 @@
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
@@ -0,0 +1,137 @@
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
@@ -0,0 +1,134 @@
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