agy-superpowers 5.1.3 → 5.1.5

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 (188) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +189 -186
  3. package/package.json +1 -1
  4. package/template/agent/patches/skills-patches.md +24 -0
  5. package/template/agent/rules/git-policy.md +25 -0
  6. package/template/agent/skills/finishing-a-development-branch/SKILL.md +18 -6
  7. package/template/agent/skills/rust-developer/SKILL.md +281 -0
  8. package/template/agent/skills/rust-developer/references/rust-rules/_sections.md +231 -0
  9. package/template/agent/skills/rust-developer/references/rust-rules/anti-clone-excessive.md +124 -0
  10. package/template/agent/skills/rust-developer/references/rust-rules/anti-collect-intermediate.md +131 -0
  11. package/template/agent/skills/rust-developer/references/rust-rules/anti-empty-catch.md +132 -0
  12. package/template/agent/skills/rust-developer/references/rust-rules/anti-expect-lazy.md +95 -0
  13. package/template/agent/skills/rust-developer/references/rust-rules/anti-format-hot-path.md +141 -0
  14. package/template/agent/skills/rust-developer/references/rust-rules/anti-index-over-iter.md +125 -0
  15. package/template/agent/skills/rust-developer/references/rust-rules/anti-lock-across-await.md +127 -0
  16. package/template/agent/skills/rust-developer/references/rust-rules/anti-over-abstraction.md +120 -0
  17. package/template/agent/skills/rust-developer/references/rust-rules/anti-panic-expected.md +131 -0
  18. package/template/agent/skills/rust-developer/references/rust-rules/anti-premature-optimize.md +156 -0
  19. package/template/agent/skills/rust-developer/references/rust-rules/anti-string-for-str.md +122 -0
  20. package/template/agent/skills/rust-developer/references/rust-rules/anti-stringly-typed.md +167 -0
  21. package/template/agent/skills/rust-developer/references/rust-rules/anti-type-erasure.md +134 -0
  22. package/template/agent/skills/rust-developer/references/rust-rules/anti-unwrap-abuse.md +143 -0
  23. package/template/agent/skills/rust-developer/references/rust-rules/anti-vec-for-slice.md +121 -0
  24. package/template/agent/skills/rust-developer/references/rust-rules/api-builder-must-use.md +143 -0
  25. package/template/agent/skills/rust-developer/references/rust-rules/api-builder-pattern.md +187 -0
  26. package/template/agent/skills/rust-developer/references/rust-rules/api-common-traits.md +165 -0
  27. package/template/agent/skills/rust-developer/references/rust-rules/api-default-impl.md +177 -0
  28. package/template/agent/skills/rust-developer/references/rust-rules/api-extension-trait.md +163 -0
  29. package/template/agent/skills/rust-developer/references/rust-rules/api-from-not-into.md +146 -0
  30. package/template/agent/skills/rust-developer/references/rust-rules/api-impl-asref.md +142 -0
  31. package/template/agent/skills/rust-developer/references/rust-rules/api-impl-into.md +160 -0
  32. package/template/agent/skills/rust-developer/references/rust-rules/api-must-use.md +125 -0
  33. package/template/agent/skills/rust-developer/references/rust-rules/api-newtype-safety.md +162 -0
  34. package/template/agent/skills/rust-developer/references/rust-rules/api-non-exhaustive.md +177 -0
  35. package/template/agent/skills/rust-developer/references/rust-rules/api-parse-dont-validate.md +184 -0
  36. package/template/agent/skills/rust-developer/references/rust-rules/api-sealed-trait.md +168 -0
  37. package/template/agent/skills/rust-developer/references/rust-rules/api-serde-optional.md +182 -0
  38. package/template/agent/skills/rust-developer/references/rust-rules/api-typestate.md +199 -0
  39. package/template/agent/skills/rust-developer/references/rust-rules/async-bounded-channel.md +175 -0
  40. package/template/agent/skills/rust-developer/references/rust-rules/async-broadcast-pubsub.md +185 -0
  41. package/template/agent/skills/rust-developer/references/rust-rules/async-cancellation-token.md +203 -0
  42. package/template/agent/skills/rust-developer/references/rust-rules/async-clone-before-await.md +171 -0
  43. package/template/agent/skills/rust-developer/references/rust-rules/async-join-parallel.md +158 -0
  44. package/template/agent/skills/rust-developer/references/rust-rules/async-joinset-structured.md +195 -0
  45. package/template/agent/skills/rust-developer/references/rust-rules/async-mpsc-queue.md +171 -0
  46. package/template/agent/skills/rust-developer/references/rust-rules/async-no-lock-await.md +156 -0
  47. package/template/agent/skills/rust-developer/references/rust-rules/async-oneshot-response.md +191 -0
  48. package/template/agent/skills/rust-developer/references/rust-rules/async-select-racing.md +198 -0
  49. package/template/agent/skills/rust-developer/references/rust-rules/async-spawn-blocking.md +154 -0
  50. package/template/agent/skills/rust-developer/references/rust-rules/async-tokio-fs.md +167 -0
  51. package/template/agent/skills/rust-developer/references/rust-rules/async-tokio-runtime.md +169 -0
  52. package/template/agent/skills/rust-developer/references/rust-rules/async-try-join.md +172 -0
  53. package/template/agent/skills/rust-developer/references/rust-rules/async-watch-latest.md +189 -0
  54. package/template/agent/skills/rust-developer/references/rust-rules/doc-all-public.md +113 -0
  55. package/template/agent/skills/rust-developer/references/rust-rules/doc-cargo-metadata.md +147 -0
  56. package/template/agent/skills/rust-developer/references/rust-rules/doc-errors-section.md +122 -0
  57. package/template/agent/skills/rust-developer/references/rust-rules/doc-examples-section.md +161 -0
  58. package/template/agent/skills/rust-developer/references/rust-rules/doc-hidden-setup.md +149 -0
  59. package/template/agent/skills/rust-developer/references/rust-rules/doc-intra-links.md +138 -0
  60. package/template/agent/skills/rust-developer/references/rust-rules/doc-link-types.md +169 -0
  61. package/template/agent/skills/rust-developer/references/rust-rules/doc-module-inner.md +116 -0
  62. package/template/agent/skills/rust-developer/references/rust-rules/doc-panics-section.md +128 -0
  63. package/template/agent/skills/rust-developer/references/rust-rules/doc-question-mark.md +136 -0
  64. package/template/agent/skills/rust-developer/references/rust-rules/doc-safety-section.md +131 -0
  65. package/template/agent/skills/rust-developer/references/rust-rules/err-anyhow-app.md +179 -0
  66. package/template/agent/skills/rust-developer/references/rust-rules/err-context-chain.md +144 -0
  67. package/template/agent/skills/rust-developer/references/rust-rules/err-custom-type.md +152 -0
  68. package/template/agent/skills/rust-developer/references/rust-rules/err-doc-errors.md +145 -0
  69. package/template/agent/skills/rust-developer/references/rust-rules/err-expect-bugs-only.md +133 -0
  70. package/template/agent/skills/rust-developer/references/rust-rules/err-from-impl.md +152 -0
  71. package/template/agent/skills/rust-developer/references/rust-rules/err-lowercase-msg.md +124 -0
  72. package/template/agent/skills/rust-developer/references/rust-rules/err-no-unwrap-prod.md +115 -0
  73. package/template/agent/skills/rust-developer/references/rust-rules/err-question-mark.md +151 -0
  74. package/template/agent/skills/rust-developer/references/rust-rules/err-result-over-panic.md +130 -0
  75. package/template/agent/skills/rust-developer/references/rust-rules/err-source-chain.md +155 -0
  76. package/template/agent/skills/rust-developer/references/rust-rules/err-thiserror-lib.md +171 -0
  77. package/template/agent/skills/rust-developer/references/rust-rules/lint-cargo-metadata.md +138 -0
  78. package/template/agent/skills/rust-developer/references/rust-rules/lint-deny-correctness.md +107 -0
  79. package/template/agent/skills/rust-developer/references/rust-rules/lint-missing-docs.md +154 -0
  80. package/template/agent/skills/rust-developer/references/rust-rules/lint-pedantic-selective.md +118 -0
  81. package/template/agent/skills/rust-developer/references/rust-rules/lint-rustfmt-check.md +157 -0
  82. package/template/agent/skills/rust-developer/references/rust-rules/lint-unsafe-doc.md +133 -0
  83. package/template/agent/skills/rust-developer/references/rust-rules/lint-warn-complexity.md +131 -0
  84. package/template/agent/skills/rust-developer/references/rust-rules/lint-warn-perf.md +136 -0
  85. package/template/agent/skills/rust-developer/references/rust-rules/lint-warn-style.md +135 -0
  86. package/template/agent/skills/rust-developer/references/rust-rules/lint-warn-suspicious.md +122 -0
  87. package/template/agent/skills/rust-developer/references/rust-rules/lint-workspace-lints.md +172 -0
  88. package/template/agent/skills/rust-developer/references/rust-rules/mem-arena-allocator.md +168 -0
  89. package/template/agent/skills/rust-developer/references/rust-rules/mem-arrayvec.md +142 -0
  90. package/template/agent/skills/rust-developer/references/rust-rules/mem-assert-type-size.md +168 -0
  91. package/template/agent/skills/rust-developer/references/rust-rules/mem-avoid-format.md +147 -0
  92. package/template/agent/skills/rust-developer/references/rust-rules/mem-box-large-variant.md +158 -0
  93. package/template/agent/skills/rust-developer/references/rust-rules/mem-boxed-slice.md +139 -0
  94. package/template/agent/skills/rust-developer/references/rust-rules/mem-clone-from.md +147 -0
  95. package/template/agent/skills/rust-developer/references/rust-rules/mem-compact-string.md +149 -0
  96. package/template/agent/skills/rust-developer/references/rust-rules/mem-reuse-collections.md +174 -0
  97. package/template/agent/skills/rust-developer/references/rust-rules/mem-smaller-integers.md +159 -0
  98. package/template/agent/skills/rust-developer/references/rust-rules/mem-smallvec.md +138 -0
  99. package/template/agent/skills/rust-developer/references/rust-rules/mem-thinvec.md +142 -0
  100. package/template/agent/skills/rust-developer/references/rust-rules/mem-with-capacity.md +156 -0
  101. package/template/agent/skills/rust-developer/references/rust-rules/mem-write-over-format.md +172 -0
  102. package/template/agent/skills/rust-developer/references/rust-rules/mem-zero-copy.md +164 -0
  103. package/template/agent/skills/rust-developer/references/rust-rules/name-acronym-word.md +99 -0
  104. package/template/agent/skills/rust-developer/references/rust-rules/name-as-free.md +104 -0
  105. package/template/agent/skills/rust-developer/references/rust-rules/name-consts-screaming.md +94 -0
  106. package/template/agent/skills/rust-developer/references/rust-rules/name-crate-no-rs.md +78 -0
  107. package/template/agent/skills/rust-developer/references/rust-rules/name-funcs-snake.md +76 -0
  108. package/template/agent/skills/rust-developer/references/rust-rules/name-into-ownership.md +123 -0
  109. package/template/agent/skills/rust-developer/references/rust-rules/name-is-has-bool.md +127 -0
  110. package/template/agent/skills/rust-developer/references/rust-rules/name-iter-convention.md +129 -0
  111. package/template/agent/skills/rust-developer/references/rust-rules/name-iter-method.md +131 -0
  112. package/template/agent/skills/rust-developer/references/rust-rules/name-iter-type-match.md +142 -0
  113. package/template/agent/skills/rust-developer/references/rust-rules/name-lifetime-short.md +86 -0
  114. package/template/agent/skills/rust-developer/references/rust-rules/name-no-get-prefix.md +154 -0
  115. package/template/agent/skills/rust-developer/references/rust-rules/name-to-expensive.md +118 -0
  116. package/template/agent/skills/rust-developer/references/rust-rules/name-type-param-single.md +92 -0
  117. package/template/agent/skills/rust-developer/references/rust-rules/name-types-camel.md +65 -0
  118. package/template/agent/skills/rust-developer/references/rust-rules/name-variants-camel.md +101 -0
  119. package/template/agent/skills/rust-developer/references/rust-rules/opt-bounds-check.md +161 -0
  120. package/template/agent/skills/rust-developer/references/rust-rules/opt-cache-friendly.md +187 -0
  121. package/template/agent/skills/rust-developer/references/rust-rules/opt-codegen-units.md +142 -0
  122. package/template/agent/skills/rust-developer/references/rust-rules/opt-cold-unlikely.md +152 -0
  123. package/template/agent/skills/rust-developer/references/rust-rules/opt-inline-always-rare.md +141 -0
  124. package/template/agent/skills/rust-developer/references/rust-rules/opt-inline-never-cold.md +181 -0
  125. package/template/agent/skills/rust-developer/references/rust-rules/opt-inline-small.md +160 -0
  126. package/template/agent/skills/rust-developer/references/rust-rules/opt-likely-hint.md +171 -0
  127. package/template/agent/skills/rust-developer/references/rust-rules/opt-lto-release.md +130 -0
  128. package/template/agent/skills/rust-developer/references/rust-rules/opt-pgo-profile.md +167 -0
  129. package/template/agent/skills/rust-developer/references/rust-rules/opt-simd-portable.md +144 -0
  130. package/template/agent/skills/rust-developer/references/rust-rules/opt-target-cpu.md +154 -0
  131. package/template/agent/skills/rust-developer/references/rust-rules/own-arc-shared.md +141 -0
  132. package/template/agent/skills/rust-developer/references/rust-rules/own-borrow-over-clone.md +95 -0
  133. package/template/agent/skills/rust-developer/references/rust-rules/own-clone-explicit.md +135 -0
  134. package/template/agent/skills/rust-developer/references/rust-rules/own-copy-small.md +124 -0
  135. package/template/agent/skills/rust-developer/references/rust-rules/own-cow-conditional.md +135 -0
  136. package/template/agent/skills/rust-developer/references/rust-rules/own-lifetime-elision.md +134 -0
  137. package/template/agent/skills/rust-developer/references/rust-rules/own-move-large.md +134 -0
  138. package/template/agent/skills/rust-developer/references/rust-rules/own-mutex-interior.md +105 -0
  139. package/template/agent/skills/rust-developer/references/rust-rules/own-rc-single-thread.md +65 -0
  140. package/template/agent/skills/rust-developer/references/rust-rules/own-refcell-interior.md +97 -0
  141. package/template/agent/skills/rust-developer/references/rust-rules/own-rwlock-readers.md +122 -0
  142. package/template/agent/skills/rust-developer/references/rust-rules/own-slice-over-vec.md +119 -0
  143. package/template/agent/skills/rust-developer/references/rust-rules/perf-black-box-bench.md +153 -0
  144. package/template/agent/skills/rust-developer/references/rust-rules/perf-chain-avoid.md +136 -0
  145. package/template/agent/skills/rust-developer/references/rust-rules/perf-collect-into.md +133 -0
  146. package/template/agent/skills/rust-developer/references/rust-rules/perf-collect-once.md +120 -0
  147. package/template/agent/skills/rust-developer/references/rust-rules/perf-drain-reuse.md +137 -0
  148. package/template/agent/skills/rust-developer/references/rust-rules/perf-entry-api.md +134 -0
  149. package/template/agent/skills/rust-developer/references/rust-rules/perf-extend-batch.md +150 -0
  150. package/template/agent/skills/rust-developer/references/rust-rules/perf-iter-lazy.md +123 -0
  151. package/template/agent/skills/rust-developer/references/rust-rules/perf-iter-over-index.md +113 -0
  152. package/template/agent/skills/rust-developer/references/rust-rules/perf-profile-first.md +175 -0
  153. package/template/agent/skills/rust-developer/references/rust-rules/perf-release-profile.md +149 -0
  154. package/template/agent/skills/rust-developer/references/rust-rules/proj-bin-dir.md +142 -0
  155. package/template/agent/skills/rust-developer/references/rust-rules/proj-flat-small.md +133 -0
  156. package/template/agent/skills/rust-developer/references/rust-rules/proj-lib-main-split.md +148 -0
  157. package/template/agent/skills/rust-developer/references/rust-rules/proj-mod-by-feature.md +130 -0
  158. package/template/agent/skills/rust-developer/references/rust-rules/proj-mod-rs-dir.md +120 -0
  159. package/template/agent/skills/rust-developer/references/rust-rules/proj-prelude-module.md +155 -0
  160. package/template/agent/skills/rust-developer/references/rust-rules/proj-pub-crate-internal.md +139 -0
  161. package/template/agent/skills/rust-developer/references/rust-rules/proj-pub-super-parent.md +135 -0
  162. package/template/agent/skills/rust-developer/references/rust-rules/proj-pub-use-reexport.md +162 -0
  163. package/template/agent/skills/rust-developer/references/rust-rules/proj-workspace-deps.md +186 -0
  164. package/template/agent/skills/rust-developer/references/rust-rules/proj-workspace-large.md +162 -0
  165. package/template/agent/skills/rust-developer/references/rust-rules/test-arrange-act-assert.md +160 -0
  166. package/template/agent/skills/rust-developer/references/rust-rules/test-cfg-test-module.md +151 -0
  167. package/template/agent/skills/rust-developer/references/rust-rules/test-criterion-bench.md +171 -0
  168. package/template/agent/skills/rust-developer/references/rust-rules/test-descriptive-names.md +142 -0
  169. package/template/agent/skills/rust-developer/references/rust-rules/test-doctest-examples.md +168 -0
  170. package/template/agent/skills/rust-developer/references/rust-rules/test-fixture-raii.md +151 -0
  171. package/template/agent/skills/rust-developer/references/rust-rules/test-integration-dir.md +144 -0
  172. package/template/agent/skills/rust-developer/references/rust-rules/test-mock-traits.md +189 -0
  173. package/template/agent/skills/rust-developer/references/rust-rules/test-mockall-mocking.md +226 -0
  174. package/template/agent/skills/rust-developer/references/rust-rules/test-proptest-properties.md +161 -0
  175. package/template/agent/skills/rust-developer/references/rust-rules/test-should-panic.md +130 -0
  176. package/template/agent/skills/rust-developer/references/rust-rules/test-tokio-async.md +154 -0
  177. package/template/agent/skills/rust-developer/references/rust-rules/test-use-super.md +127 -0
  178. package/template/agent/skills/rust-developer/references/rust-rules/type-enum-states.md +154 -0
  179. package/template/agent/skills/rust-developer/references/rust-rules/type-generic-bounds.md +142 -0
  180. package/template/agent/skills/rust-developer/references/rust-rules/type-never-diverge.md +146 -0
  181. package/template/agent/skills/rust-developer/references/rust-rules/type-newtype-ids.md +160 -0
  182. package/template/agent/skills/rust-developer/references/rust-rules/type-newtype-validated.md +159 -0
  183. package/template/agent/skills/rust-developer/references/rust-rules/type-no-stringly.md +144 -0
  184. package/template/agent/skills/rust-developer/references/rust-rules/type-option-nullable.md +137 -0
  185. package/template/agent/skills/rust-developer/references/rust-rules/type-phantom-marker.md +188 -0
  186. package/template/agent/skills/rust-developer/references/rust-rules/type-repr-transparent.md +143 -0
  187. package/template/agent/skills/rust-developer/references/rust-rules/type-result-fallible.md +131 -0
  188. package/template/agent/skills/using-git-worktrees/SKILL.md +3 -1
@@ -0,0 +1,147 @@
1
+ # mem-avoid-format
2
+
3
+ > Avoid `format!()` when string literals work
4
+
5
+ ## Why It Matters
6
+
7
+ `format!()` always allocates a new String, even for constant text. In hot paths, these allocations add up. Use string literals, `write!()`, or pre-allocated buffers instead.
8
+
9
+ ## Bad
10
+
11
+ ```rust
12
+ // Allocates every time, even for static text
13
+ fn get_error_message() -> String {
14
+ format!("An error occurred") // Unnecessary allocation!
15
+ }
16
+
17
+ // Allocates in a loop
18
+ for item in items {
19
+ log::info!("{}", format!("Processing item: {}", item)); // Double work!
20
+ }
21
+
22
+ // format! in hot path
23
+ fn classify(n: i32) -> String {
24
+ if n > 0 {
25
+ format!("positive") // Allocates!
26
+ } else if n < 0 {
27
+ format!("negative") // Allocates!
28
+ } else {
29
+ format!("zero") // Allocates!
30
+ }
31
+ }
32
+ ```
33
+
34
+ ## Good
35
+
36
+ ```rust
37
+ // Return &'static str for constants
38
+ fn get_error_message() -> &'static str {
39
+ "An error occurred" // No allocation
40
+ }
41
+
42
+ // Use format args directly
43
+ for item in items {
44
+ log::info!("Processing item: {}", item); // No intermediate String
45
+ }
46
+
47
+ // Return Cow for mixed static/dynamic
48
+ use std::borrow::Cow;
49
+
50
+ fn classify(n: i32) -> Cow<'static, str> {
51
+ if n > 0 {
52
+ Cow::Borrowed("positive") // No allocation
53
+ } else if n < 0 {
54
+ Cow::Borrowed("negative") // No allocation
55
+ } else {
56
+ Cow::Borrowed("zero") // No allocation
57
+ }
58
+ }
59
+
60
+ // Or just &'static str if always static
61
+ fn classify_str(n: i32) -> &'static str {
62
+ if n > 0 { "positive" }
63
+ else if n < 0 { "negative" }
64
+ else { "zero" }
65
+ }
66
+ ```
67
+
68
+ ## Use write!() for Output
69
+
70
+ ```rust
71
+ use std::io::Write;
72
+
73
+ // Bad: Allocate then write
74
+ fn bad_log(writer: &mut impl Write, msg: &str, code: u32) {
75
+ let formatted = format!("[ERROR {}] {}", code, msg); // Allocation!
76
+ writer.write_all(formatted.as_bytes()).unwrap();
77
+ }
78
+
79
+ // Good: Write directly
80
+ fn good_log(writer: &mut impl Write, msg: &str, code: u32) {
81
+ write!(writer, "[ERROR {}] {}", code, msg).unwrap(); // No allocation!
82
+ }
83
+ ```
84
+
85
+ ## Pre-allocate for Multiple Appends
86
+
87
+ ```rust
88
+ // Bad: Multiple allocations
89
+ fn build_message(parts: &[&str]) -> String {
90
+ let mut result = String::new();
91
+ for part in parts {
92
+ result = format!("{}{}\n", result, part); // Allocates each iteration!
93
+ }
94
+ result
95
+ }
96
+
97
+ // Good: Pre-allocate
98
+ fn build_message(parts: &[&str]) -> String {
99
+ let total_len: usize = parts.iter().map(|p| p.len() + 1).sum();
100
+ let mut result = String::with_capacity(total_len);
101
+ for part in parts {
102
+ result.push_str(part);
103
+ result.push('\n');
104
+ }
105
+ result
106
+ }
107
+
108
+ // Good: Use join
109
+ fn build_message(parts: &[&str]) -> String {
110
+ parts.join("\n")
111
+ }
112
+ ```
113
+
114
+ ## CompactString for Small Strings
115
+
116
+ ```rust
117
+ use compact_str::CompactString;
118
+
119
+ // Stack-allocated for strings <= 24 bytes
120
+ fn format_code(code: u32) -> CompactString {
121
+ compact_str::format_compact!("ERR-{:04}", code)
122
+ // Stack-allocated if result is small enough
123
+ }
124
+ ```
125
+
126
+ ## When format!() Is Fine
127
+
128
+ ```rust
129
+ // Rare/cold paths - clarity over micro-optimization
130
+ fn log_startup_message() {
131
+ println!("{}", format!("Starting {} v{}", APP_NAME, VERSION));
132
+ }
133
+
134
+ // When you need an owned String anyway
135
+ fn create_user_greeting(name: &str) -> String {
136
+ format!("Hello, {}!", name) // Need owned String
137
+ }
138
+
139
+ // Error messages (already on error path)
140
+ return Err(format!("Invalid value: {}", value).into());
141
+ ```
142
+
143
+ ## See Also
144
+
145
+ - [mem-write-over-format](mem-write-over-format.md) - Use write!() instead of format!()
146
+ - [mem-with-capacity](mem-with-capacity.md) - Pre-allocate strings
147
+ - [own-cow-conditional](own-cow-conditional.md) - Use Cow for mixed static/dynamic
@@ -0,0 +1,158 @@
1
+ # mem-box-large-variant
2
+
3
+ > Box large enum variants to reduce overall enum size
4
+
5
+ ## Why It Matters
6
+
7
+ An enum's size is determined by its largest variant. If one variant contains a large struct while others are small, every instance of the enum pays for the largest variant's size. Boxing the large variant puts that data on the heap, keeping the enum itself small. This can significantly reduce memory usage and improve cache performance.
8
+
9
+ ## Bad
10
+
11
+ ```rust
12
+ enum Message {
13
+ Quit, // 0 bytes of data
14
+ Move { x: i32, y: i32 }, // 8 bytes
15
+ Text(String), // 24 bytes
16
+ Image {
17
+ data: [u8; 1024], // 1024 bytes - forces entire enum to ~1032 bytes!
18
+ width: u32,
19
+ height: u32
20
+ },
21
+ }
22
+
23
+ // Every Message is ~1032 bytes, even Quit and Move
24
+ let messages: Vec<Message> = vec![
25
+ Message::Quit, // Wastes ~1032 bytes
26
+ Message::Quit, // Wastes ~1032 bytes
27
+ Message::Move { x: 0, y: 0 }, // Wastes ~1024 bytes
28
+ ];
29
+ ```
30
+
31
+ ## Good
32
+
33
+ ```rust
34
+ struct ImageData {
35
+ data: [u8; 1024],
36
+ width: u32,
37
+ height: u32,
38
+ }
39
+
40
+ enum Message {
41
+ Quit,
42
+ Move { x: i32, y: i32 },
43
+ Text(String),
44
+ Image(Box<ImageData>), // Now just 8 bytes (pointer)
45
+ }
46
+
47
+ // Message is now ~32 bytes (String variant is largest)
48
+ let messages: Vec<Message> = vec![
49
+ Message::Quit, // Uses ~32 bytes
50
+ Message::Quit, // Uses ~32 bytes
51
+ Message::Move { x: 0, y: 0 }, // Uses ~32 bytes
52
+ ];
53
+ ```
54
+
55
+ ## Check Enum Sizes
56
+
57
+ ```rust
58
+ use std::mem::size_of;
59
+
60
+ // Before boxing
61
+ enum BadEvent {
62
+ Click { x: u32, y: u32 }, // 8 bytes
63
+ KeyPress(char), // 4 bytes
64
+ LargeData([u8; 256]), // 256 bytes
65
+ }
66
+ println!("BadEvent: {} bytes", size_of::<BadEvent>()); // ~264 bytes
67
+
68
+ // After boxing
69
+ enum GoodEvent {
70
+ Click { x: u32, y: u32 },
71
+ KeyPress(char),
72
+ LargeData(Box<[u8; 256]>), // 8 bytes (pointer)
73
+ }
74
+ println!("GoodEvent: {} bytes", size_of::<GoodEvent>()); // ~16 bytes
75
+ ```
76
+
77
+ ## Clippy Lint
78
+
79
+ ```toml
80
+ [lints.clippy]
81
+ large_enum_variant = "warn" # Warns when variants differ significantly
82
+ ```
83
+
84
+ ```rust
85
+ // Clippy will suggest:
86
+ // warning: large size difference between variants
87
+ // help: consider boxing the large fields to reduce the total size
88
+ ```
89
+
90
+ ## When to Box
91
+
92
+ | Largest Variant | Other Variants | Action |
93
+ |-----------------|----------------|--------|
94
+ | < 64 bytes | Similar size | Don't box |
95
+ | > 128 bytes | Much smaller | Box the large variant |
96
+ | > 256 bytes | Any | Definitely box |
97
+
98
+ ## Recursive Types Require Boxing
99
+
100
+ ```rust
101
+ // Won't compile - infinite size
102
+ enum List {
103
+ Cons(i32, List),
104
+ Nil,
105
+ }
106
+
107
+ // Must box recursive variant
108
+ enum List {
109
+ Cons(i32, Box<List>), // Now finite size
110
+ Nil,
111
+ }
112
+
113
+ // Same for ASTs
114
+ enum Expr {
115
+ Number(i64),
116
+ BinOp {
117
+ op: Op,
118
+ left: Box<Expr>, // Recursive - must box
119
+ right: Box<Expr>,
120
+ },
121
+ }
122
+ ```
123
+
124
+ ## Pattern Matching with Boxed Variants
125
+
126
+ ```rust
127
+ enum Event {
128
+ Small(u32),
129
+ Large(Box<LargeData>),
130
+ }
131
+
132
+ fn handle(event: Event) {
133
+ match event {
134
+ Event::Small(n) => println!("Small: {}", n),
135
+ Event::Large(data) => {
136
+ // data is Box<LargeData>, dereference to access
137
+ println!("Large: {} bytes", data.size);
138
+ }
139
+ }
140
+ }
141
+
142
+ // Or match on reference
143
+ fn handle_ref(event: &Event) {
144
+ match event {
145
+ Event::Small(n) => println!("Small: {}", n),
146
+ Event::Large(data) => {
147
+ // data is &Box<LargeData>, auto-derefs
148
+ println!("Large: {} bytes", data.size);
149
+ }
150
+ }
151
+ }
152
+ ```
153
+
154
+ ## See Also
155
+
156
+ - [own-move-large](./own-move-large.md) - Boxing large types for cheap moves
157
+ - [mem-smallvec](./mem-smallvec.md) - Alternative for inline small collections
158
+ - [lint-deny-correctness](./lint-deny-correctness.md) - Enabling clippy lints
@@ -0,0 +1,139 @@
1
+ # mem-boxed-slice
2
+
3
+ > Use `Box<[T]>` instead of `Vec<T>` for fixed-size heap data
4
+
5
+ ## Why It Matters
6
+
7
+ `Vec<T>` stores three words: pointer, length, and capacity. When you know a collection won't grow, `Box<[T]>` stores only pointer and length (2 words), saving 8 bytes per instance. More importantly, it communicates intent: "this data is fixed-size." For large numbers of fixed collections, this adds up.
8
+
9
+ ## Bad
10
+
11
+ ```rust
12
+ struct Document {
13
+ // Vec signals "might grow" but we never push after creation
14
+ paragraphs: Vec<Paragraph>, // 24 bytes: ptr + len + capacity
15
+ }
16
+
17
+ fn load_document(data: &[u8]) -> Document {
18
+ let paragraphs: Vec<Paragraph> = parse_paragraphs(data);
19
+ // paragraphs has capacity >= len, wasting the capacity field
20
+ Document { paragraphs }
21
+ }
22
+ ```
23
+
24
+ ## Good
25
+
26
+ ```rust
27
+ struct Document {
28
+ // Box<[T]> signals "fixed size" - clear intent
29
+ paragraphs: Box<[Paragraph]>, // 16 bytes: ptr + len (as fat pointer)
30
+ }
31
+
32
+ fn load_document(data: &[u8]) -> Document {
33
+ let paragraphs: Vec<Paragraph> = parse_paragraphs(data);
34
+ Document {
35
+ paragraphs: paragraphs.into_boxed_slice() // Shrinks + converts
36
+ }
37
+ }
38
+ ```
39
+
40
+ ## Memory Layout
41
+
42
+ ```rust
43
+ use std::mem::size_of;
44
+
45
+ // Vec: 24 bytes on 64-bit
46
+ assert_eq!(size_of::<Vec<u8>>(), 24); // ptr(8) + len(8) + cap(8)
47
+
48
+ // Box<[T]>: 16 bytes (fat pointer)
49
+ assert_eq!(size_of::<Box<[u8]>>(), 16); // ptr(8) + len(8)
50
+
51
+ // Savings per instance: 8 bytes
52
+ // For 1 million instances: 8 MB saved
53
+ ```
54
+
55
+ ## Conversion Patterns
56
+
57
+ ```rust
58
+ // Vec to Box<[T]>
59
+ let vec: Vec<i32> = vec![1, 2, 3, 4, 5];
60
+ let boxed: Box<[i32]> = vec.into_boxed_slice();
61
+
62
+ // Box<[T]> back to Vec (if you need to grow)
63
+ let vec_again: Vec<i32> = boxed.into_vec();
64
+
65
+ // From iterator
66
+ let boxed: Box<[i32]> = (0..100).collect::<Vec<_>>().into_boxed_slice();
67
+
68
+ // Shrink Vec first if it has excess capacity
69
+ let mut vec = Vec::with_capacity(1000);
70
+ vec.extend(0..10);
71
+ vec.shrink_to_fit(); // Reduce capacity to length
72
+ let boxed = vec.into_boxed_slice(); // Now no wasted allocation
73
+ ```
74
+
75
+ ## When to Use What
76
+
77
+ | Type | Use When |
78
+ |------|----------|
79
+ | `Vec<T>` | Collection may grow/shrink |
80
+ | `Box<[T]>` | Fixed-size, heap-allocated, many instances |
81
+ | `[T; N]` | Fixed-size, stack-allocated, size known at compile time |
82
+ | `&[T]` | Borrowed view, don't need ownership |
83
+
84
+ ## Box<str> for Immutable Strings
85
+
86
+ Same principle applies to strings:
87
+
88
+ ```rust
89
+ use std::mem::size_of;
90
+
91
+ // String: 24 bytes (like Vec<u8>)
92
+ assert_eq!(size_of::<String>(), 24);
93
+
94
+ // Box<str>: 16 bytes
95
+ assert_eq!(size_of::<Box<str>>(), 16);
96
+
97
+ // For immutable strings
98
+ struct Name {
99
+ value: Box<str>, // Saves 8 bytes vs String
100
+ }
101
+
102
+ impl Name {
103
+ fn new(s: &str) -> Self {
104
+ Name { value: s.into() } // &str -> Box<str>
105
+ }
106
+ }
107
+
108
+ // Or from String
109
+ let s = String::from("hello");
110
+ let boxed: Box<str> = s.into_boxed_str();
111
+ ```
112
+
113
+ ## Real-World Example
114
+
115
+ ```rust
116
+ // Cache with millions of entries
117
+ struct Cache {
118
+ // 8 bytes saved per entry adds up
119
+ entries: HashMap<Key, Box<[u8]>>,
120
+ }
121
+
122
+ impl Cache {
123
+ fn insert(&mut self, key: Key, data: Vec<u8>) {
124
+ // Convert to boxed slice for storage
125
+ self.entries.insert(key, data.into_boxed_slice());
126
+ }
127
+
128
+ fn get(&self, key: &Key) -> Option<&[u8]> {
129
+ // Returns regular slice reference
130
+ self.entries.get(key).map(|b| b.as_ref())
131
+ }
132
+ }
133
+ ```
134
+
135
+ ## See Also
136
+
137
+ - [mem-with-capacity](./mem-with-capacity.md) - Pre-allocating when size is known
138
+ - [own-slice-over-vec](./own-slice-over-vec.md) - Using slices in function parameters
139
+ - [mem-compact-string](./mem-compact-string.md) - Compact string alternatives
@@ -0,0 +1,147 @@
1
+ # mem-clone-from
2
+
3
+ > Use `clone_from()` to reuse allocations when repeatedly cloning
4
+
5
+ ## Why It Matters
6
+
7
+ `x = y.clone()` drops x's allocation and creates a new one from y. `x.clone_from(&y)` reuses x's existing allocation if possible, avoiding the allocation overhead. For repeatedly cloning into the same variable (loops, buffers), this can significantly reduce allocator pressure.
8
+
9
+ ## Bad
10
+
11
+ ```rust
12
+ let mut buffer = String::with_capacity(1024);
13
+
14
+ for source in sources {
15
+ buffer = source.clone(); // Drops old allocation, allocates new
16
+ process(&buffer);
17
+ }
18
+
19
+ // Each iteration:
20
+ // 1. Drops buffer's 1024-byte allocation
21
+ // 2. Allocates new memory for source.clone()
22
+ // Allocator thrashing!
23
+ ```
24
+
25
+ ## Good
26
+
27
+ ```rust
28
+ let mut buffer = String::with_capacity(1024);
29
+
30
+ for source in sources {
31
+ buffer.clone_from(source); // Reuses allocation if capacity sufficient
32
+ process(&buffer);
33
+ }
34
+
35
+ // If source.len() <= 1024, no allocation happens
36
+ // Just copies bytes into existing buffer
37
+ ```
38
+
39
+ ## How clone_from Works
40
+
41
+ ```rust
42
+ impl Clone for String {
43
+ fn clone(&self) -> Self {
44
+ // Always allocates new memory
45
+ String::from(self.as_str())
46
+ }
47
+
48
+ fn clone_from(&mut self, source: &Self) {
49
+ // Reuse existing capacity if possible
50
+ self.clear();
51
+ self.push_str(source); // Only reallocates if capacity insufficient
52
+ }
53
+ }
54
+ ```
55
+
56
+ ## Types That Benefit
57
+
58
+ ```rust
59
+ // String - reuses capacity
60
+ let mut s = String::with_capacity(100);
61
+ s.clone_from(&other_string);
62
+
63
+ // Vec<T> - reuses capacity
64
+ let mut v: Vec<u8> = Vec::with_capacity(1000);
65
+ v.clone_from(&other_vec);
66
+
67
+ // HashMap - reuses buckets
68
+ let mut map = HashMap::with_capacity(100);
69
+ map.clone_from(&other_map);
70
+
71
+ // PathBuf - reuses capacity
72
+ let mut path = PathBuf::with_capacity(256);
73
+ path.clone_from(&other_path);
74
+ ```
75
+
76
+ ## Benchmarking the Difference
77
+
78
+ ```rust
79
+ use criterion::{black_box, criterion_group, Criterion};
80
+
81
+ fn bench_clone_patterns(c: &mut Criterion) {
82
+ let source = "x".repeat(1000);
83
+
84
+ c.bench_function("clone assignment", |b| {
85
+ let mut buffer = String::new();
86
+ b.iter(|| {
87
+ buffer = black_box(&source).clone();
88
+ });
89
+ });
90
+
91
+ c.bench_function("clone_from", |b| {
92
+ let mut buffer = String::with_capacity(1000);
93
+ b.iter(|| {
94
+ buffer.clone_from(black_box(&source));
95
+ });
96
+ });
97
+ }
98
+ // clone_from is typically 2-3x faster for this pattern
99
+ ```
100
+
101
+ ## Custom Implementations
102
+
103
+ When implementing Clone for your types:
104
+
105
+ ```rust
106
+ #[derive(Debug)]
107
+ struct Buffer {
108
+ data: Vec<u8>,
109
+ metadata: Metadata,
110
+ }
111
+
112
+ impl Clone for Buffer {
113
+ fn clone(&self) -> Self {
114
+ Buffer {
115
+ data: self.data.clone(),
116
+ metadata: self.metadata.clone(),
117
+ }
118
+ }
119
+
120
+ // Optimize clone_from to reuse vec capacity
121
+ fn clone_from(&mut self, source: &Self) {
122
+ self.data.clone_from(&source.data); // Reuses allocation
123
+ self.metadata = source.metadata.clone();
124
+ }
125
+ }
126
+ ```
127
+
128
+ ## When NOT Needed
129
+
130
+ ```rust
131
+ // Single clone - no benefit
132
+ let copy = original.clone(); // Can't reuse, no prior allocation
133
+
134
+ // Small Copy types - no allocation anyway
135
+ let x: i32 = y; // Not even Clone, just Copy
136
+
137
+ // Immutable context
138
+ fn process(data: &String) {
139
+ // Can't use clone_from - would need &mut self
140
+ }
141
+ ```
142
+
143
+ ## See Also
144
+
145
+ - [mem-with-capacity](./mem-with-capacity.md) - Pre-allocating capacity
146
+ - [mem-reuse-collections](./mem-reuse-collections.md) - Reusing collection allocations
147
+ - [own-clone-explicit](./own-clone-explicit.md) - When Clone is appropriate