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,135 @@
1
+ # own-clone-explicit
2
+
3
+ > Use explicit `Clone` for types where copying has meaningful cost
4
+
5
+ ## Why It Matters
6
+
7
+ Unlike `Copy` which is implicit and "free," `Clone` requires an explicit `.clone()` call, signaling that duplication has a cost. This makes heap allocations and deep copies visible in code, helping developers reason about performance. Types with heap data (`String`, `Vec`, `Box`) should implement `Clone` but not `Copy`.
8
+
9
+ ## Bad
10
+
11
+ ```rust
12
+ // Hiding expensive operations
13
+ fn process_data(data: Vec<u32>) -> Vec<u32> {
14
+ let backup = data; // Moved, not copied - but unclear at call site
15
+ transform(backup)
16
+ }
17
+
18
+ let my_data = vec![1, 2, 3, 4, 5];
19
+ let result = process_data(my_data);
20
+ // my_data is moved - surprise if you expected it to still exist
21
+ ```
22
+
23
+ ## Good
24
+
25
+ ```rust
26
+ fn process_data(data: Vec<u32>) -> Vec<u32> {
27
+ let backup = data;
28
+ transform(backup)
29
+ }
30
+
31
+ let my_data = vec![1, 2, 3, 4, 5];
32
+ let result = process_data(my_data.clone()); // Explicit: "I know this allocates"
33
+ // my_data still available
34
+
35
+ // Or better - take reference if you don't need ownership
36
+ fn process_data_ref(data: &[u32]) -> Vec<u32> {
37
+ transform(data)
38
+ }
39
+ let result = process_data_ref(&my_data); // No clone needed
40
+ ```
41
+
42
+ ## Custom Clone Implementation
43
+
44
+ For types with mixed cheap/expensive fields, implement `Clone` manually:
45
+
46
+ ```rust
47
+ #[derive(Debug)]
48
+ struct Document {
49
+ id: u64, // Cheap to copy
50
+ content: String, // Expensive to clone
51
+ metadata: Metadata, // Moderate cost
52
+ }
53
+
54
+ impl Clone for Document {
55
+ fn clone(&self) -> Self {
56
+ Self {
57
+ id: self.id,
58
+ content: self.content.clone(),
59
+ metadata: self.metadata.clone(),
60
+ }
61
+ }
62
+
63
+ // Optimization: reuse existing allocations
64
+ fn clone_from(&mut self, source: &Self) {
65
+ self.id = source.id;
66
+ self.content.clone_from(&source.content); // Reuses capacity
67
+ self.metadata.clone_from(&source.metadata);
68
+ }
69
+ }
70
+ ```
71
+
72
+ ## clone_from Optimization
73
+
74
+ `clone_from` can reuse existing allocations:
75
+
76
+ ```rust
77
+ let mut buffer = String::with_capacity(1000);
78
+
79
+ // Bad: drops old allocation, creates new one
80
+ buffer = source.clone();
81
+
82
+ // Good: reuses existing capacity if sufficient
83
+ buffer.clone_from(&source);
84
+ ```
85
+
86
+ ## Derive vs Manual Clone
87
+
88
+ ```rust
89
+ // Derive when all fields need cloning
90
+ #[derive(Clone)]
91
+ struct Simple {
92
+ data: Vec<u8>,
93
+ name: String,
94
+ }
95
+
96
+ // Manual when you need special behavior
97
+ struct CachedValue {
98
+ value: i32,
99
+ cache: RefCell<Option<ExpensiveComputation>>,
100
+ }
101
+
102
+ impl Clone for CachedValue {
103
+ fn clone(&self) -> Self {
104
+ Self {
105
+ value: self.value,
106
+ cache: RefCell::new(None), // Don't clone cache, let it rebuild
107
+ }
108
+ }
109
+ }
110
+ ```
111
+
112
+ ## When to Avoid Clone
113
+
114
+ ```rust
115
+ // Instead of cloning, consider:
116
+
117
+ // 1. References
118
+ fn process(data: &MyType) { } // Borrow instead of clone
119
+
120
+ // 2. Cow for conditional cloning
121
+ fn process(data: Cow<'_, str>) { } // Clone only if mutation needed
122
+
123
+ // 3. Arc for shared ownership
124
+ let shared = Arc::new(expensive_data);
125
+ let handle = shared.clone(); // Cheap: just increments counter
126
+
127
+ // 4. Passing by value when caller is done with it
128
+ fn consume(data: MyType) { } // Caller moves, no clone
129
+ ```
130
+
131
+ ## See Also
132
+
133
+ - [own-copy-small](./own-copy-small.md) - When implicit Copy is appropriate
134
+ - [own-cow-conditional](./own-cow-conditional.md) - Avoiding clones with Cow
135
+ - [mem-clone-from](./mem-clone-from.md) - Optimizing repeated clones
@@ -0,0 +1,124 @@
1
+ # own-copy-small
2
+
3
+ > Implement `Copy` for small, simple types
4
+
5
+ ## Why It Matters
6
+
7
+ Types that implement `Copy` are implicitly duplicated on assignment instead of moved. This eliminates the need for explicit `.clone()` calls and makes the code more ergonomic. For small types (generally ≤16 bytes), copying is as fast or faster than moving a pointer.
8
+
9
+ ## Bad
10
+
11
+ ```rust
12
+ // Small type without Copy - requires explicit clone
13
+ #[derive(Clone, Debug)]
14
+ struct Point {
15
+ x: f64,
16
+ y: f64,
17
+ }
18
+
19
+ fn distance(p1: Point, p2: Point) -> f64 {
20
+ ((p2.x - p1.x).powi(2) + (p2.y - p1.y).powi(2)).sqrt()
21
+ }
22
+
23
+ let origin = Point { x: 0.0, y: 0.0 };
24
+ let target = Point { x: 3.0, y: 4.0 };
25
+
26
+ let d1 = distance(origin.clone(), target.clone()); // Tedious
27
+ let d2 = distance(origin.clone(), target.clone()); // Every use needs clone
28
+ // origin and target still usable but verbose
29
+ ```
30
+
31
+ ## Good
32
+
33
+ ```rust
34
+ // Small type with Copy - implicit duplication
35
+ #[derive(Clone, Copy, Debug)]
36
+ struct Point {
37
+ x: f64,
38
+ y: f64,
39
+ }
40
+
41
+ fn distance(p1: Point, p2: Point) -> f64 {
42
+ ((p2.x - p1.x).powi(2) + (p2.y - p1.y).powi(2)).sqrt()
43
+ }
44
+
45
+ let origin = Point { x: 0.0, y: 0.0 };
46
+ let target = Point { x: 3.0, y: 4.0 };
47
+
48
+ let d1 = distance(origin, target); // Implicitly copied
49
+ let d2 = distance(origin, target); // Still works!
50
+ // origin and target remain valid
51
+ ```
52
+
53
+ ## Copy Requirements
54
+
55
+ A type can implement `Copy` only if:
56
+ 1. All fields implement `Copy`
57
+ 2. No custom `Drop` implementation
58
+ 3. No heap-allocated data (`String`, `Vec`, `Box`, etc.)
59
+
60
+ ```rust
61
+ // ✅ Can be Copy
62
+ #[derive(Clone, Copy)]
63
+ struct Color {
64
+ r: u8,
65
+ g: u8,
66
+ b: u8,
67
+ a: u8,
68
+ }
69
+
70
+ // ❌ Cannot be Copy - contains String
71
+ #[derive(Clone)]
72
+ struct Person {
73
+ name: String, // String is not Copy
74
+ age: u32,
75
+ }
76
+
77
+ // ❌ Cannot be Copy - has Drop
78
+ struct FileHandle {
79
+ fd: i32,
80
+ }
81
+ impl Drop for FileHandle {
82
+ fn drop(&mut self) { /* close file */ }
83
+ }
84
+ ```
85
+
86
+ ## Size Guidelines
87
+
88
+ | Size | Recommendation |
89
+ |------|----------------|
90
+ | ≤ 16 bytes | Implement `Copy` |
91
+ | 17-64 bytes | Consider `Copy`, benchmark if critical |
92
+ | > 64 bytes | Probably don't, prefer references |
93
+
94
+ ```rust
95
+ use std::mem::size_of;
96
+
97
+ #[derive(Clone, Copy)]
98
+ struct SmallId(u64); // 8 bytes ✅
99
+
100
+ #[derive(Clone, Copy)]
101
+ struct Rect { x: f32, y: f32, w: f32, h: f32 } // 16 bytes ✅
102
+
103
+ #[derive(Clone)] // No Copy - 72 bytes
104
+ struct Transform {
105
+ matrix: [[f64; 3]; 3], // 72 bytes, too large
106
+ }
107
+ ```
108
+
109
+ ## Common Copy Types
110
+
111
+ Standard library types that are `Copy`:
112
+ - All primitives: `i32`, `f64`, `bool`, `char`, etc.
113
+ - References: `&T`, `&mut T`
114
+ - Raw pointers: `*const T`, `*mut T`
115
+ - Function pointers: `fn(T) -> U`
116
+ - Tuples of `Copy` types: `(i32, f64)`
117
+ - Arrays of `Copy` types: `[u8; 32]`
118
+ - `Option<T>` where `T: Copy`
119
+ - `PhantomData<T>`
120
+
121
+ ## See Also
122
+
123
+ - [own-clone-explicit](./own-clone-explicit.md) - When Clone without Copy is appropriate
124
+ - [type-newtype-ids](./type-newtype-ids.md) - Newtype pattern often uses Copy
@@ -0,0 +1,135 @@
1
+ # own-cow-conditional
2
+
3
+ > Use `Cow<'a, T>` for conditional ownership
4
+
5
+ ## Why It Matters
6
+
7
+ `Cow` (Clone-on-Write) lets you avoid allocations when you *might* need to own data but usually don't. It holds either a borrowed reference or an owned value, cloning only when mutation is needed.
8
+
9
+ ## Bad
10
+
11
+ ```rust
12
+ // Always allocates, even when input doesn't need modification
13
+ fn normalize_path(path: &str) -> String {
14
+ if path.contains("//") {
15
+ path.replace("//", "/") // Allocation needed
16
+ } else {
17
+ path.to_string() // Unnecessary allocation!
18
+ }
19
+ }
20
+
21
+ // Always clones the error message
22
+ fn format_error(code: u32) -> String {
23
+ match code {
24
+ 404 => "Not Found".to_string(), // Unnecessary!
25
+ 500 => "Internal Error".to_string(), // Unnecessary!
26
+ _ => format!("Error {}", code), // This one needs allocation
27
+ }
28
+ }
29
+ ```
30
+
31
+ ## Good
32
+
33
+ ```rust
34
+ use std::borrow::Cow;
35
+
36
+ // Only allocates when needed
37
+ fn normalize_path(path: &str) -> Cow<'_, str> {
38
+ if path.contains("//") {
39
+ Cow::Owned(path.replace("//", "/")) // Allocate
40
+ } else {
41
+ Cow::Borrowed(path) // Zero-cost borrow
42
+ }
43
+ }
44
+
45
+ // Static strings stay borrowed
46
+ fn format_error(code: u32) -> Cow<'static, str> {
47
+ match code {
48
+ 404 => Cow::Borrowed("Not Found"), // No allocation
49
+ 500 => Cow::Borrowed("Internal Error"), // No allocation
50
+ _ => Cow::Owned(format!("Error {}", code)), // Allocate only for unknown
51
+ }
52
+ }
53
+ ```
54
+
55
+ ## Real-World Example from ripgrep
56
+
57
+ ```rust
58
+ // https://github.com/BurntSushi/ripgrep/blob/master/crates/globset/src/pathutil.rs
59
+ pub(crate) fn file_name<'a>(path: &Cow<'a, [u8]>) -> Option<Cow<'a, [u8]>> {
60
+ let last_slash = path.rfind_byte(b'/').map(|i| i + 1).unwrap_or(0);
61
+ match *path {
62
+ Cow::Borrowed(path) => Some(Cow::Borrowed(&path[last_slash..])),
63
+ Cow::Owned(ref path) => {
64
+ let mut path = path.clone();
65
+ path.drain_bytes(..last_slash);
66
+ Some(Cow::Owned(path))
67
+ }
68
+ }
69
+ }
70
+ ```
71
+
72
+ ## Clone-on-Write Pattern
73
+
74
+ ```rust
75
+ use std::borrow::Cow;
76
+
77
+ fn process_text(text: Cow<'_, str>) -> Cow<'_, str> {
78
+ if text.contains("bad_word") {
79
+ // to_mut() clones if borrowed, returns &mut if owned
80
+ let mut owned = text.into_owned();
81
+ owned = owned.replace("bad_word", "***");
82
+ Cow::Owned(owned)
83
+ } else {
84
+ text // Pass through unchanged
85
+ }
86
+ }
87
+
88
+ // Usage
89
+ let borrowed: Cow<str> = Cow::Borrowed("hello world");
90
+ let result = process_text(borrowed); // No allocation!
91
+
92
+ let with_bad: Cow<str> = Cow::Borrowed("hello bad_word");
93
+ let result = process_text(with_bad); // Allocates only here
94
+ ```
95
+
96
+ ## Cow with Collections
97
+
98
+ ```rust
99
+ use std::borrow::Cow;
100
+
101
+ // Mixed borrowed/owned in a collection
102
+ fn collect_errors<'a>(
103
+ static_errors: &[&'static str],
104
+ dynamic_errors: Vec<String>,
105
+ ) -> Vec<Cow<'a, str>> {
106
+ let mut errors: Vec<Cow<str>> = Vec::new();
107
+
108
+ // Static strings - no allocation
109
+ for &e in static_errors {
110
+ errors.push(Cow::Borrowed(e));
111
+ }
112
+
113
+ // Dynamic strings - take ownership
114
+ for e in dynamic_errors {
115
+ errors.push(Cow::Owned(e));
116
+ }
117
+
118
+ errors
119
+ }
120
+ ```
121
+
122
+ ## When to Use Cow
123
+
124
+ | Situation | Use Cow? |
125
+ |-----------|----------|
126
+ | Usually borrow, sometimes own | Yes |
127
+ | Always need owned data | No, just use owned type |
128
+ | Always borrow | No, just use reference |
129
+ | Hot path, avoiding all allocations | Yes |
130
+ | Returning static strings or formatted | Yes |
131
+
132
+ ## See Also
133
+
134
+ - [own-borrow-over-clone](own-borrow-over-clone.md) - Prefer borrowing over cloning
135
+ - [mem-avoid-format](mem-avoid-format.md) - Avoid format! when possible
@@ -0,0 +1,134 @@
1
+ # own-lifetime-elision
2
+
3
+ > Rely on lifetime elision rules; add explicit lifetimes only when required
4
+
5
+ ## Why It Matters
6
+
7
+ Rust's lifetime elision rules handle most common borrowing patterns automatically. Adding explicit lifetimes where they're not needed clutters code without adding clarity. However, understanding when elision applies helps you know when explicit lifetimes are truly necessary.
8
+
9
+ ## Bad
10
+
11
+ ```rust
12
+ // Unnecessary explicit lifetimes - elision handles these
13
+ fn first_word<'a>(s: &'a str) -> &'a str {
14
+ s.split_whitespace().next().unwrap_or("")
15
+ }
16
+
17
+ fn get_name<'a>(person: &'a Person) -> &'a str {
18
+ &person.name
19
+ }
20
+
21
+ impl<'a> Display for Wrapper<'a> {
22
+ fn fmt<'b>(&'b self, f: &'b mut Formatter<'_>) -> fmt::Result {
23
+ write!(f, "{}", self.0)
24
+ }
25
+ }
26
+ ```
27
+
28
+ ## Good
29
+
30
+ ```rust
31
+ // Let elision do its job
32
+ fn first_word(s: &str) -> &str {
33
+ s.split_whitespace().next().unwrap_or("")
34
+ }
35
+
36
+ fn get_name(person: &Person) -> &str {
37
+ &person.name
38
+ }
39
+
40
+ impl Display for Wrapper<'_> {
41
+ fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
42
+ write!(f, "{}", self.0)
43
+ }
44
+ }
45
+ ```
46
+
47
+ ## The Three Elision Rules
48
+
49
+ 1. **Each input reference gets its own lifetime:**
50
+ ```rust
51
+ fn foo(x: &str, y: &str)
52
+ // becomes
53
+ fn foo<'a, 'b>(x: &'a str, y: &'b str)
54
+ ```
55
+
56
+ 2. **One input reference → output gets same lifetime:**
57
+ ```rust
58
+ fn foo(x: &str) -> &str
59
+ // becomes
60
+ fn foo<'a>(x: &'a str) -> &'a str
61
+ ```
62
+
63
+ 3. **Method with `&self`/`&mut self` → output gets self's lifetime:**
64
+ ```rust
65
+ fn foo(&self, x: &str) -> &str
66
+ // becomes
67
+ fn foo<'a, 'b>(&'a self, x: &'b str) -> &'a str
68
+ ```
69
+
70
+ ## When Explicit Lifetimes ARE Required
71
+
72
+ ```rust
73
+ // Multiple input references, output could come from either
74
+ fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
75
+ if x.len() > y.len() { x } else { y }
76
+ }
77
+
78
+ // Struct holding references
79
+ struct Parser<'input> {
80
+ source: &'input str,
81
+ position: usize,
82
+ }
83
+
84
+ // Multiple distinct lifetimes needed
85
+ struct Context<'s, 'c> {
86
+ source: &'s str,
87
+ cache: &'c mut Cache,
88
+ }
89
+
90
+ // Static lifetime for constants
91
+ fn get_default() -> &'static str {
92
+ "default"
93
+ }
94
+ ```
95
+
96
+ ## Anonymous Lifetime `'_`
97
+
98
+ Use `'_` to let the compiler infer while being explicit about the presence of a lifetime:
99
+
100
+ ```rust
101
+ // In struct definitions
102
+ impl Iterator for Parser<'_> {
103
+ type Item = Token;
104
+ fn next(&mut self) -> Option<Self::Item> { ... }
105
+ }
106
+
107
+ // In function signatures where it adds clarity
108
+ fn parse(input: &str) -> Result<Ast<'_>, Error> { ... }
109
+
110
+ // Especially useful in trait bounds
111
+ fn process(data: &impl AsRef<str>) -> Cow<'_, str> { ... }
112
+ ```
113
+
114
+ ## Common Patterns
115
+
116
+ ```rust
117
+ // ✅ Elision works
118
+ fn trim(s: &str) -> &str { s.trim() }
119
+ fn first(v: &[i32]) -> Option<&i32> { v.first() }
120
+ fn name(&self) -> &str { &self.name }
121
+
122
+ // ❌ Elision fails - multiple inputs, ambiguous output
123
+ fn pick(a: &str, b: &str, first: bool) -> &str // Error!
124
+
125
+ // ✅ Fixed with explicit lifetime
126
+ fn pick<'a>(a: &'a str, b: &'a str, first: bool) -> &'a str {
127
+ if first { a } else { b }
128
+ }
129
+ ```
130
+
131
+ ## See Also
132
+
133
+ - [own-borrow-over-clone](./own-borrow-over-clone.md) - Prefer borrowing to avoid ownership issues
134
+ - [api-impl-asref](./api-impl-asref.md) - Generic borrowing with AsRef
@@ -0,0 +1,134 @@
1
+ # own-move-large
2
+
3
+ > Move large types instead of copying; use `Box` if moves are expensive
4
+
5
+ ## Why It Matters
6
+
7
+ In Rust, "moving" a value means copying its bytes to a new location and invalidating the old one. For large types (hundreds of bytes), this memcpy can be expensive. Boxing large types reduces move cost to copying a single pointer (8 bytes), making moves cheap regardless of the actual data size.
8
+
9
+ ## Bad
10
+
11
+ ```rust
12
+ // Large struct moved repeatedly = expensive memcpy each time
13
+ struct GameState {
14
+ board: [[Cell; 100]; 100], // 10,000 cells
15
+ history: [Move; 1000], // 1,000 moves
16
+ players: [Player; 4], // Player data
17
+ // Total: potentially tens of KB
18
+ }
19
+
20
+ fn process_state(state: GameState) -> GameState {
21
+ // Moving ~40KB+ of data
22
+ let mut new_state = state; // Memcpy here
23
+ new_state.apply_rules();
24
+ new_state // Memcpy on return
25
+ }
26
+
27
+ let state = GameState::new();
28
+ let state = process_state(state); // Two large memcpys
29
+ ```
30
+
31
+ ## Good
32
+
33
+ ```rust
34
+ // Box reduces move cost to 8 bytes
35
+ struct GameState {
36
+ board: Box<[[Cell; 100]; 100]>, // Pointer to heap
37
+ history: Vec<Move>, // Already heap-allocated
38
+ players: [Player; 4],
39
+ }
40
+
41
+ fn process_state(mut state: GameState) -> GameState {
42
+ // Moving just pointers + small inline data
43
+ state.apply_rules();
44
+ state // Cheap move
45
+ }
46
+
47
+ // Or use Box at call site for one-off cases
48
+ fn process_large(state: Box<LargeStruct>) -> Box<LargeStruct> {
49
+ // 8-byte move regardless of LargeStruct size
50
+ state
51
+ }
52
+ ```
53
+
54
+ ## When to Box
55
+
56
+ | Type Size | Move Frequency | Recommendation |
57
+ |-----------|----------------|----------------|
58
+ | < 128 bytes | Any | Don't box |
59
+ | 128-512 bytes | Rare | Probably don't box |
60
+ | 128-512 bytes | Frequent | Consider boxing |
61
+ | > 512 bytes | Any | Box or use references |
62
+ | > 4KB | Any | Definitely box |
63
+
64
+ ## Stack vs Heap Tradeoffs
65
+
66
+ ```rust
67
+ // Stack: fast allocation, limited size, moves copy bytes
68
+ struct StackHeavy {
69
+ data: [u8; 4096], // 4KB on stack
70
+ }
71
+
72
+ // Heap: allocation cost, unlimited size, moves copy pointer
73
+ struct HeapLight {
74
+ data: Box<[u8; 4096]>, // 8 bytes on stack, 4KB on heap
75
+ }
76
+
77
+ // Measure with size_of
78
+ use std::mem::size_of;
79
+ assert_eq!(size_of::<StackHeavy>(), 4096);
80
+ assert_eq!(size_of::<HeapLight>(), 8);
81
+ ```
82
+
83
+ ## Alternative: References
84
+
85
+ When you don't need ownership transfer, use references:
86
+
87
+ ```rust
88
+ // Best: no move at all
89
+ fn analyze_state(state: &GameState) -> Analysis {
90
+ // Borrows state, no copying
91
+ compute_analysis(state)
92
+ }
93
+
94
+ // Mutable borrow for in-place modification
95
+ fn update_state(state: &mut GameState) {
96
+ state.tick();
97
+ }
98
+ ```
99
+
100
+ ## Pattern: Builder Returns Boxed
101
+
102
+ ```rust
103
+ impl LargeConfig {
104
+ pub fn builder() -> ConfigBuilder {
105
+ ConfigBuilder::default()
106
+ }
107
+ }
108
+
109
+ impl ConfigBuilder {
110
+ // Return boxed to avoid large move
111
+ pub fn build(self) -> Box<LargeConfig> {
112
+ Box::new(LargeConfig {
113
+ // ... fields from builder
114
+ })
115
+ }
116
+ }
117
+ ```
118
+
119
+ ## Profile First
120
+
121
+ Don't prematurely optimize. Use tools to identify if moves are actually a bottleneck:
122
+
123
+ ```rust
124
+ // Check type sizes
125
+ println!("Size of GameState: {}", std::mem::size_of::<GameState>());
126
+
127
+ // Profile with cargo flamegraph or perf to find hot memcpys
128
+ ```
129
+
130
+ ## See Also
131
+
132
+ - [own-copy-small](./own-copy-small.md) - Cheap types should be Copy
133
+ - [mem-box-large-variant](./mem-box-large-variant.md) - Boxing enum variants
134
+ - [perf-profile-first](./perf-profile-first.md) - Measure before optimizing