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,122 @@
1
+ # anti-string-for-str
2
+
3
+ > Don't accept &String when &str works
4
+
5
+ ## Why It Matters
6
+
7
+ `&String` is strictly less flexible than `&str`. A `&str` can be created from `String`, `&str`, literals, and slices. A `&String` requires exactly a `String`. This forces callers to allocate when they might not need to.
8
+
9
+ ## Bad
10
+
11
+ ```rust
12
+ // Forces callers to have a String
13
+ fn greet(name: &String) {
14
+ println!("Hello, {}", name);
15
+ }
16
+
17
+ // Caller must allocate
18
+ greet(&"Alice".to_string()); // Unnecessary allocation
19
+ greet(&name); // Only works if name is String
20
+
21
+ // In struct
22
+ struct Config {
23
+ name: String,
24
+ }
25
+
26
+ impl Config {
27
+ fn set_name(&mut self, name: &String) { // Too restrictive
28
+ self.name = name.clone();
29
+ }
30
+ }
31
+ ```
32
+
33
+ ## Good
34
+
35
+ ```rust
36
+ // Accept &str - works with String, &str, literals
37
+ fn greet(name: &str) {
38
+ println!("Hello, {}", name);
39
+ }
40
+
41
+ // All these work
42
+ greet("Alice"); // String literal
43
+ greet(&name); // &String coerces to &str
44
+ greet(name.as_str()); // Explicit &str
45
+
46
+ // In struct
47
+ impl Config {
48
+ fn set_name(&mut self, name: &str) {
49
+ self.name = name.to_string();
50
+ }
51
+
52
+ // Or accept owned String if caller usually has one
53
+ fn set_name_owned(&mut self, name: String) {
54
+ self.name = name;
55
+ }
56
+
57
+ // Or be generic
58
+ fn set_name_into(&mut self, name: impl Into<String>) {
59
+ self.name = name.into();
60
+ }
61
+ }
62
+ ```
63
+
64
+ ## Deref Coercion
65
+
66
+ `String` implements `Deref<Target = str>`, so `&String` automatically coerces to `&str`:
67
+
68
+ ```rust
69
+ fn takes_str(s: &str) { }
70
+
71
+ let owned = String::from("hello");
72
+ takes_str(&owned); // &String -> &str via Deref
73
+ ```
74
+
75
+ ## When to Accept &String
76
+
77
+ Rarely. Maybe if you need `String`-specific methods:
78
+
79
+ ```rust
80
+ fn needs_capacity(s: &String) -> usize {
81
+ s.capacity() // Only String has capacity()
82
+ }
83
+ ```
84
+
85
+ But usually you'd take `&str` and let the caller manage the `String`.
86
+
87
+ ## Pattern: Flexible APIs
88
+
89
+ ```rust
90
+ // Most flexible: accept anything that can become &str
91
+ fn process(input: impl AsRef<str>) {
92
+ let s: &str = input.as_ref();
93
+ // ...
94
+ }
95
+
96
+ process("literal");
97
+ process(String::from("owned"));
98
+ process(&some_string);
99
+ ```
100
+
101
+ ## Similar Anti-patterns
102
+
103
+ | Anti-pattern | Better |
104
+ |--------------|--------|
105
+ | `&String` | `&str` |
106
+ | `&Vec<T>` | `&[T]` |
107
+ | `&Box<T>` | `&T` |
108
+ | `&PathBuf` | `&Path` |
109
+ | `&OsString` | `&OsStr` |
110
+
111
+ ## Clippy Detection
112
+
113
+ ```toml
114
+ [lints.clippy]
115
+ ptr_arg = "warn" # Catches &String, &Vec, &PathBuf
116
+ ```
117
+
118
+ ## See Also
119
+
120
+ - [anti-vec-for-slice](./anti-vec-for-slice.md) - Similar pattern for Vec
121
+ - [own-slice-over-vec](./own-slice-over-vec.md) - Slice patterns
122
+ - [api-impl-asref](./api-impl-asref.md) - AsRef pattern
@@ -0,0 +1,167 @@
1
+ # anti-stringly-typed
2
+
3
+ > Don't use strings where enums or newtypes would provide type safety
4
+
5
+ ## Why It Matters
6
+
7
+ Strings are the most primitive way to represent data—they accept any value, provide no validation, and offer no IDE support. When you have a fixed set of valid values or a semantic type, use enums or newtypes. The compiler catches mistakes at compile time instead of runtime.
8
+
9
+ ## Bad
10
+
11
+ ```rust
12
+ fn process_order(status: &str, priority: &str) {
13
+ // What are valid statuses? "pending"? "Pending"? "PENDING"?
14
+ // What are valid priorities? "high"? "1"? "urgent"?
15
+ match status {
16
+ "pending" => { ... }
17
+ "completed" => { ... }
18
+ _ => panic!("unknown status"), // Runtime error
19
+ }
20
+ }
21
+
22
+ struct User {
23
+ email: String, // Any string, even "not an email"
24
+ phone: String, // Any string, even "hello"
25
+ user_id: String, // Could be confused with other string IDs
26
+ }
27
+
28
+ // Easy to make mistakes
29
+ process_order("complete", "high"); // Typo: "complete" vs "completed"
30
+ process_order("high", "pending"); // Swapped arguments - compiles!
31
+ ```
32
+
33
+ ## Good
34
+
35
+ ```rust
36
+ #[derive(Debug, Clone, Copy, PartialEq, Eq)]
37
+ enum OrderStatus {
38
+ Pending,
39
+ Processing,
40
+ Completed,
41
+ Cancelled,
42
+ }
43
+
44
+ #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
45
+ enum Priority {
46
+ Low,
47
+ Medium,
48
+ High,
49
+ Critical,
50
+ }
51
+
52
+ fn process_order(status: OrderStatus, priority: Priority) {
53
+ match status {
54
+ OrderStatus::Pending => { ... }
55
+ OrderStatus::Processing => { ... }
56
+ OrderStatus::Completed => { ... }
57
+ OrderStatus::Cancelled => { ... }
58
+ } // Exhaustive - compiler checks all cases
59
+ }
60
+
61
+ // Validated newtypes
62
+ struct Email(String);
63
+ struct PhoneNumber(String);
64
+ struct UserId(u64);
65
+
66
+ impl Email {
67
+ pub fn new(s: &str) -> Result<Self, ValidationError> {
68
+ if is_valid_email(s) {
69
+ Ok(Email(s.to_string()))
70
+ } else {
71
+ Err(ValidationError::InvalidEmail)
72
+ }
73
+ }
74
+ }
75
+
76
+ struct User {
77
+ email: Email, // Must be valid email
78
+ phone: PhoneNumber, // Must be valid phone
79
+ user_id: UserId, // Can't confuse with other IDs
80
+ }
81
+
82
+ // Compile errors catch mistakes
83
+ process_order(OrderStatus::Completed, Priority::High); // Clear and correct
84
+ process_order(Priority::High, OrderStatus::Pending); // Compile error!
85
+ ```
86
+
87
+ ## Parsing Strings to Types
88
+
89
+ ```rust
90
+ use std::str::FromStr;
91
+
92
+ #[derive(Debug, Clone, Copy)]
93
+ enum OrderStatus {
94
+ Pending,
95
+ Processing,
96
+ Completed,
97
+ Cancelled,
98
+ }
99
+
100
+ impl FromStr for OrderStatus {
101
+ type Err = ParseError;
102
+
103
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
104
+ match s.to_lowercase().as_str() {
105
+ "pending" => Ok(OrderStatus::Pending),
106
+ "processing" => Ok(OrderStatus::Processing),
107
+ "completed" => Ok(OrderStatus::Completed),
108
+ "cancelled" | "canceled" => Ok(OrderStatus::Cancelled),
109
+ _ => Err(ParseError::UnknownStatus(s.to_string())),
110
+ }
111
+ }
112
+ }
113
+
114
+ // Parse at boundary, use types internally
115
+ fn handle_request(status_str: &str) -> Result<(), Error> {
116
+ let status: OrderStatus = status_str.parse()?; // Validate once
117
+ process_order(status); // Type-safe from here
118
+ Ok(())
119
+ }
120
+ ```
121
+
122
+ ## With Serde
123
+
124
+ ```rust
125
+ use serde::{Serialize, Deserialize};
126
+
127
+ #[derive(Debug, Clone, Serialize, Deserialize)]
128
+ #[serde(rename_all = "snake_case")]
129
+ enum Status {
130
+ Pending,
131
+ InProgress,
132
+ Completed,
133
+ }
134
+
135
+ // JSON: {"status": "in_progress"}
136
+ // Deserialization validates automatically
137
+ ```
138
+
139
+ ## Error Messages
140
+
141
+ ```rust
142
+ #[derive(Debug, Clone, Copy)]
143
+ enum Color {
144
+ Red,
145
+ Green,
146
+ Blue,
147
+ }
148
+
149
+ impl std::fmt::Display for Color {
150
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
151
+ match self {
152
+ Color::Red => write!(f, "red"),
153
+ Color::Green => write!(f, "green"),
154
+ Color::Blue => write!(f, "blue"),
155
+ }
156
+ }
157
+ }
158
+
159
+ // Type-safe and displayable
160
+ println!("Selected color: {}", Color::Red);
161
+ ```
162
+
163
+ ## See Also
164
+
165
+ - [api-newtype-safety](./api-newtype-safety.md) - Newtype pattern
166
+ - [api-parse-dont-validate](./api-parse-dont-validate.md) - Parse at boundaries
167
+ - [type-newtype-ids](./type-newtype-ids.md) - Type-safe IDs
@@ -0,0 +1,134 @@
1
+ # anti-type-erasure
2
+
3
+ > Don't use Box<dyn Trait> when impl Trait works
4
+
5
+ ## Why It Matters
6
+
7
+ `Box<dyn Trait>` (type erasure) introduces heap allocation and dynamic dispatch overhead. When you have a single concrete type or can use generics, `impl Trait` provides the same flexibility with zero overhead through monomorphization.
8
+
9
+ ## Bad
10
+
11
+ ```rust
12
+ // Unnecessary type erasure
13
+ fn get_iterator() -> Box<dyn Iterator<Item = i32>> {
14
+ Box::new((0..10).map(|x| x * 2))
15
+ }
16
+
17
+ // Boxing for no reason
18
+ fn make_handler() -> Box<dyn Fn(i32) -> i32> {
19
+ Box::new(|x| x + 1)
20
+ }
21
+
22
+ // Vec of boxed trait objects when one type would do
23
+ fn get_validators() -> Vec<Box<dyn Validator>> {
24
+ vec![
25
+ Box::new(LengthValidator),
26
+ Box::new(RegexValidator),
27
+ ]
28
+ }
29
+ ```
30
+
31
+ ## Good
32
+
33
+ ```rust
34
+ // impl Trait - zero overhead, inlined
35
+ fn get_iterator() -> impl Iterator<Item = i32> {
36
+ (0..10).map(|x| x * 2)
37
+ }
38
+
39
+ // impl Fn - no boxing
40
+ fn make_handler() -> impl Fn(i32) -> i32 {
41
+ |x| x + 1
42
+ }
43
+
44
+ // When mixed types are genuinely needed, Box is OK
45
+ fn get_validators() -> Vec<Box<dyn Validator>> {
46
+ // Actually different types at runtime - Box is appropriate
47
+ config.validators.iter()
48
+ .map(|v| v.create_validator())
49
+ .collect()
50
+ }
51
+ ```
52
+
53
+ ## When to Use Box<dyn Trait>
54
+
55
+ Type erasure IS appropriate when:
56
+
57
+ ```rust
58
+ // Heterogeneous collection of different types
59
+ let handlers: Vec<Box<dyn Handler>> = vec![
60
+ Box::new(LogHandler),
61
+ Box::new(MetricsHandler),
62
+ Box::new(AuthHandler),
63
+ ];
64
+
65
+ // Type cannot be known at compile time
66
+ fn create_from_config(config: &Config) -> Box<dyn Database> {
67
+ match config.db_type {
68
+ DbType::Postgres => Box::new(PostgresDb::new()),
69
+ DbType::Sqlite => Box::new(SqliteDb::new()),
70
+ }
71
+ }
72
+
73
+ // Recursive types
74
+ struct Node {
75
+ value: i32,
76
+ children: Vec<Box<dyn NodeTrait>>,
77
+ }
78
+
79
+ // Breaking cycles in complex ownership
80
+ struct EventLoop {
81
+ handlers: Vec<Box<dyn EventHandler>>,
82
+ }
83
+ ```
84
+
85
+ ## Comparison
86
+
87
+ | Approach | Allocation | Dispatch | Binary Size |
88
+ |----------|------------|----------|-------------|
89
+ | `impl Trait` | Stack/inline | Static | Larger (monomorphization) |
90
+ | `Box<dyn Trait>` | Heap | Dynamic | Smaller |
91
+ | Generics `<T>` | Stack/inline | Static | Larger |
92
+
93
+ ## impl Trait Positions
94
+
95
+ ```rust
96
+ // Return position - caller doesn't need to know concrete type
97
+ fn process() -> impl Future<Output = Result> { }
98
+
99
+ // Argument position - like generics but simpler
100
+ fn handle(handler: impl Handler) { }
101
+
102
+ // Can't use in trait definitions (use associated types instead)
103
+ trait Processor {
104
+ type Output: Display; // Not impl Display
105
+ fn process(&self) -> Self::Output;
106
+ }
107
+ ```
108
+
109
+ ## Pattern: Enum Instead of dyn
110
+
111
+ ```rust
112
+ // Instead of Box<dyn Shape>
113
+ enum Shape {
114
+ Circle { radius: f64 },
115
+ Rectangle { width: f64, height: f64 },
116
+ Triangle { base: f64, height: f64 },
117
+ }
118
+
119
+ impl Shape {
120
+ fn area(&self) -> f64 {
121
+ match self {
122
+ Shape::Circle { radius } => PI * radius * radius,
123
+ Shape::Rectangle { width, height } => width * height,
124
+ Shape::Triangle { base, height } => 0.5 * base * height,
125
+ }
126
+ }
127
+ }
128
+ ```
129
+
130
+ ## See Also
131
+
132
+ - [anti-over-abstraction](./anti-over-abstraction.md) - Excessive generics
133
+ - [type-generic-bounds](./type-generic-bounds.md) - Generic constraints
134
+ - [mem-box-large-variant](./mem-box-large-variant.md) - Boxing enum variants
@@ -0,0 +1,143 @@
1
+ # anti-unwrap-abuse
2
+
3
+ > Don't use `.unwrap()` in production code
4
+
5
+ ## Why It Matters
6
+
7
+ `.unwrap()` panics on `None` or `Err`, crashing your program. In production, this means lost data, failed requests, and unhappy users. It also makes debugging harder since panic messages often lack context.
8
+
9
+ ## Bad
10
+
11
+ ```rust
12
+ // Crashes if file doesn't exist
13
+ let content = std::fs::read_to_string("config.toml").unwrap();
14
+
15
+ // Crashes on invalid input
16
+ let num: i32 = user_input.parse().unwrap();
17
+
18
+ // Crashes if key missing
19
+ let value = map.get("key").unwrap();
20
+
21
+ // Crashes if channel closed
22
+ let msg = receiver.recv().unwrap();
23
+ ```
24
+
25
+ ## Good
26
+
27
+ ```rust
28
+ // Propagate with ?
29
+ fn load_config() -> Result<Config, Error> {
30
+ let content = std::fs::read_to_string("config.toml")?;
31
+ Ok(toml::from_str(&content)?)
32
+ }
33
+
34
+ // Provide default
35
+ let num: i32 = user_input.parse().unwrap_or(0);
36
+
37
+ // Handle missing key
38
+ let value = map.get("key").ok_or(Error::MissingKey)?;
39
+
40
+ // Or use if-let
41
+ if let Some(value) = map.get("key") {
42
+ process(value);
43
+ }
44
+
45
+ // Channel with proper handling
46
+ match receiver.recv() {
47
+ Ok(msg) => handle(msg),
48
+ Err(_) => break, // Channel closed
49
+ }
50
+ ```
51
+
52
+ ## When unwrap() Is Acceptable
53
+
54
+ ```rust
55
+ // 1. Tests - panics are expected failures
56
+ #[test]
57
+ fn test_parse() {
58
+ let result = parse("valid").unwrap(); // OK in tests
59
+ assert_eq!(result, expected);
60
+ }
61
+
62
+ // 2. Const/static initialization (compile-time guaranteed)
63
+ static REGEX: Lazy<Regex> = Lazy::new(|| {
64
+ Regex::new(r"^\d+$").unwrap() // Known-valid pattern
65
+ });
66
+
67
+ // 3. After a check that guarantees success
68
+ if map.contains_key("key") {
69
+ let value = map.get("key").unwrap(); // Just checked
70
+ }
71
+ // Better: use if-let or entry API instead
72
+
73
+ // 4. Truly impossible cases with proof comment
74
+ let last = vec.pop().unwrap();
75
+ // OK only if you just checked !vec.is_empty()
76
+ // Better: use last() or pattern match
77
+ ```
78
+
79
+ ## Alternatives to unwrap()
80
+
81
+ ```rust
82
+ // unwrap_or - provide default
83
+ let x = opt.unwrap_or(default);
84
+
85
+ // unwrap_or_default - use Default trait
86
+ let x = opt.unwrap_or_default();
87
+
88
+ // unwrap_or_else - compute default lazily
89
+ let x = opt.unwrap_or_else(|| expensive_default());
90
+
91
+ // ? operator - propagate errors
92
+ let x = opt.ok_or(Error::Missing)?;
93
+
94
+ // if let - handle Some/Ok case
95
+ if let Some(x) = opt {
96
+ use_x(x);
97
+ }
98
+
99
+ // match - handle all cases
100
+ match opt {
101
+ Some(x) => use_x(x),
102
+ None => handle_none(),
103
+ }
104
+
105
+ // map - transform if present
106
+ let y = opt.map(|x| x + 1);
107
+
108
+ // and_then - chain fallible operations
109
+ let z = opt.and_then(|x| x.checked_add(1));
110
+ ```
111
+
112
+ ## expect() Is Slightly Better
113
+
114
+ ```rust
115
+ // unwrap() - no context
116
+ let file = File::open(path).unwrap();
117
+ // Panics with: "called `Result::unwrap()` on an `Err` value: Os { code: 2, ... }"
118
+
119
+ // expect() - adds context
120
+ let file = File::open(path)
121
+ .expect("config file should exist at startup");
122
+ // Panics with: "config file should exist at startup: Os { code: 2, ... }"
123
+
124
+ // But still use only for invariants, not error handling
125
+ ```
126
+
127
+ ## Clippy Lint
128
+
129
+ ```rust
130
+ // Enable these lints to catch unwrap usage:
131
+ #![warn(clippy::unwrap_used)]
132
+ #![warn(clippy::expect_used)] // Stricter
133
+
134
+ // Or per-function:
135
+ #[allow(clippy::unwrap_used)]
136
+ fn tests_only() { }
137
+ ```
138
+
139
+ ## See Also
140
+
141
+ - [err-question-mark](err-question-mark.md) - Use ? for propagation
142
+ - [err-result-over-panic](err-result-over-panic.md) - Return Result instead of panicking
143
+ - [anti-expect-lazy](anti-expect-lazy.md) - Don't use expect for recoverable errors
@@ -0,0 +1,121 @@
1
+ # anti-vec-for-slice
2
+
3
+ > Don't accept &Vec<T> when &[T] works
4
+
5
+ ## Why It Matters
6
+
7
+ `&Vec<T>` is strictly less flexible than `&[T]`. A slice can be created from `Vec`, arrays, and other slice-like types. Accepting `&Vec<T>` forces callers to have exactly a `Vec`, preventing them from using arrays, slices, or other collections.
8
+
9
+ ## Bad
10
+
11
+ ```rust
12
+ // Forces callers to have a Vec
13
+ fn sum(numbers: &Vec<i32>) -> i32 {
14
+ numbers.iter().sum()
15
+ }
16
+
17
+ // Caller must allocate
18
+ let arr = [1, 2, 3, 4, 5];
19
+ sum(&arr.to_vec()); // Unnecessary allocation
20
+
21
+ // Slice won't work
22
+ let slice: &[i32] = &[1, 2, 3];
23
+ // sum(slice); // Error: expected &Vec<i32>
24
+ ```
25
+
26
+ ## Good
27
+
28
+ ```rust
29
+ // Accept slice - works with Vec, arrays, slices
30
+ fn sum(numbers: &[i32]) -> i32 {
31
+ numbers.iter().sum()
32
+ }
33
+
34
+ // All these work
35
+ sum(&[1, 2, 3, 4, 5]); // Array
36
+ sum(&vec![1, 2, 3]); // Vec
37
+ sum(&numbers[1..3]); // Slice of slice
38
+ sum(numbers.as_slice()); // Explicit slice
39
+ ```
40
+
41
+ ## Deref Coercion
42
+
43
+ `Vec<T>` implements `Deref<Target = [T]>`, so `&Vec<T>` automatically coerces to `&[T]`:
44
+
45
+ ```rust
46
+ fn takes_slice(s: &[i32]) { }
47
+
48
+ let vec = vec![1, 2, 3];
49
+ takes_slice(&vec); // &Vec<i32> -> &[i32] via Deref
50
+ ```
51
+
52
+ ## Mutable Slices
53
+
54
+ Same applies to `&mut`:
55
+
56
+ ```rust
57
+ // Bad
58
+ fn double(numbers: &mut Vec<i32>) {
59
+ for n in numbers.iter_mut() {
60
+ *n *= 2;
61
+ }
62
+ }
63
+
64
+ // Good
65
+ fn double(numbers: &mut [i32]) {
66
+ for n in numbers.iter_mut() {
67
+ *n *= 2;
68
+ }
69
+ }
70
+ ```
71
+
72
+ ## When to Accept &Vec<T>
73
+
74
+ Rarely. Only when you need Vec-specific operations:
75
+
76
+ ```rust
77
+ fn needs_capacity(v: &Vec<i32>) -> usize {
78
+ v.capacity() // Only Vec has capacity
79
+ }
80
+
81
+ fn might_grow(v: &mut Vec<i32>) {
82
+ v.push(42); // Slice can't push
83
+ }
84
+ ```
85
+
86
+ ## Pattern: Accepting Multiple Types
87
+
88
+ ```rust
89
+ // Accept anything that can be viewed as a slice
90
+ fn process<T: AsRef<[u8]>>(data: T) {
91
+ let bytes: &[u8] = data.as_ref();
92
+ // ...
93
+ }
94
+
95
+ process(&[1u8, 2, 3]); // Array
96
+ process(vec![1u8, 2, 3]); // Vec
97
+ process(&some_vec); // &Vec
98
+ process(b"bytes"); // Byte string
99
+ ```
100
+
101
+ ## Similar Anti-patterns
102
+
103
+ | Anti-pattern | Better |
104
+ |--------------|--------|
105
+ | `&Vec<T>` | `&[T]` |
106
+ | `&String` | `&str` |
107
+ | `&PathBuf` | `&Path` |
108
+ | `&Box<T>` | `&T` |
109
+
110
+ ## Clippy Detection
111
+
112
+ ```toml
113
+ [lints.clippy]
114
+ ptr_arg = "warn" # Catches &Vec, &String, &PathBuf
115
+ ```
116
+
117
+ ## See Also
118
+
119
+ - [anti-string-for-str](./anti-string-for-str.md) - Similar for String
120
+ - [own-slice-over-vec](./own-slice-over-vec.md) - Slice patterns
121
+ - [api-impl-asref](./api-impl-asref.md) - AsRef pattern