agy-superpowers 5.2.2 → 5.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (231) hide show
  1. package/README.md +47 -150
  2. package/package.json +1 -1
  3. package/template/agent/rules/CLAUDE.md +80 -0
  4. package/template/agent/rules/code-styles.md +31 -32
  5. package/template/agent/rules/debug-confirmation-policy.md +2 -0
  6. package/template/agent/rules/file-length-policy.md +2 -0
  7. package/template/agent/rules/git-policy.md +7 -0
  8. package/template/agent/rules/language-matching.md +2 -0
  9. package/template/agent/rules/scratch-scripts.md +39 -0
  10. package/template/agent/rules/superpowers.md +8 -51
  11. package/template/agent/skills/executing-plans/SKILL.md +17 -0
  12. package/template/agent/skills/systematic-debugging/SKILL.md +16 -0
  13. package/template/agent/skills/test-driven-development/SKILL.md +16 -0
  14. package/template/agent/skills/verification-before-completion/SKILL.md +22 -0
  15. package/template/agent/skills/writing-plans/SKILL.md +16 -0
  16. package/template/agent/skills/ai-integrated-product/SKILL.md +0 -57
  17. package/template/agent/skills/analytics-setup/SKILL.md +0 -51
  18. package/template/agent/skills/api-design/SKILL.md +0 -193
  19. package/template/agent/skills/app-store-optimizer/SKILL.md +0 -127
  20. package/template/agent/skills/auth-and-identity/SKILL.md +0 -167
  21. package/template/agent/skills/backend-developer/SKILL.md +0 -148
  22. package/template/agent/skills/bootstrapper-finance/SKILL.md +0 -55
  23. package/template/agent/skills/chrome-extension-developer/SKILL.md +0 -53
  24. package/template/agent/skills/community-manager/SKILL.md +0 -115
  25. package/template/agent/skills/content-marketer/SKILL.md +0 -111
  26. package/template/agent/skills/conversion-optimizer/SKILL.md +0 -142
  27. package/template/agent/skills/cto-architect/SKILL.md +0 -133
  28. package/template/agent/skills/customer-success-manager/SKILL.md +0 -126
  29. package/template/agent/skills/data-analyst/SKILL.md +0 -147
  30. package/template/agent/skills/devops-engineer/SKILL.md +0 -117
  31. package/template/agent/skills/email-infrastructure/SKILL.md +0 -164
  32. package/template/agent/skills/game-design/SKILL.md +0 -194
  33. package/template/agent/skills/game-developer/SKILL.md +0 -175
  34. package/template/agent/skills/growth-hacker/SKILL.md +0 -122
  35. package/template/agent/skills/idea-validator/SKILL.md +0 -55
  36. package/template/agent/skills/indie-legal/SKILL.md +0 -53
  37. package/template/agent/skills/influencer-marketer/SKILL.md +0 -141
  38. package/template/agent/skills/landing-page-builder/SKILL.md +0 -59
  39. package/template/agent/skills/launch-strategist/SKILL.md +0 -62
  40. package/template/agent/skills/market-researcher/SKILL.md +0 -53
  41. package/template/agent/skills/micro-saas-builder/SKILL.md +0 -56
  42. package/template/agent/skills/monetization-strategist/SKILL.md +0 -119
  43. package/template/agent/skills/paid-acquisition-specialist/SKILL.md +0 -119
  44. package/template/agent/skills/pricing-psychologist/SKILL.md +0 -58
  45. package/template/agent/skills/real-time-features/SKILL.md +0 -194
  46. package/template/agent/skills/retention-specialist/SKILL.md +0 -123
  47. package/template/agent/skills/rust-developer/SKILL.md +0 -281
  48. package/template/agent/skills/rust-developer/references/rust-rules/_sections.md +0 -231
  49. package/template/agent/skills/rust-developer/references/rust-rules/anti-clone-excessive.md +0 -124
  50. package/template/agent/skills/rust-developer/references/rust-rules/anti-collect-intermediate.md +0 -131
  51. package/template/agent/skills/rust-developer/references/rust-rules/anti-empty-catch.md +0 -132
  52. package/template/agent/skills/rust-developer/references/rust-rules/anti-expect-lazy.md +0 -95
  53. package/template/agent/skills/rust-developer/references/rust-rules/anti-format-hot-path.md +0 -141
  54. package/template/agent/skills/rust-developer/references/rust-rules/anti-index-over-iter.md +0 -125
  55. package/template/agent/skills/rust-developer/references/rust-rules/anti-lock-across-await.md +0 -127
  56. package/template/agent/skills/rust-developer/references/rust-rules/anti-over-abstraction.md +0 -120
  57. package/template/agent/skills/rust-developer/references/rust-rules/anti-panic-expected.md +0 -131
  58. package/template/agent/skills/rust-developer/references/rust-rules/anti-premature-optimize.md +0 -156
  59. package/template/agent/skills/rust-developer/references/rust-rules/anti-string-for-str.md +0 -122
  60. package/template/agent/skills/rust-developer/references/rust-rules/anti-stringly-typed.md +0 -167
  61. package/template/agent/skills/rust-developer/references/rust-rules/anti-type-erasure.md +0 -134
  62. package/template/agent/skills/rust-developer/references/rust-rules/anti-unwrap-abuse.md +0 -143
  63. package/template/agent/skills/rust-developer/references/rust-rules/anti-vec-for-slice.md +0 -121
  64. package/template/agent/skills/rust-developer/references/rust-rules/api-builder-must-use.md +0 -143
  65. package/template/agent/skills/rust-developer/references/rust-rules/api-builder-pattern.md +0 -187
  66. package/template/agent/skills/rust-developer/references/rust-rules/api-common-traits.md +0 -165
  67. package/template/agent/skills/rust-developer/references/rust-rules/api-default-impl.md +0 -177
  68. package/template/agent/skills/rust-developer/references/rust-rules/api-extension-trait.md +0 -163
  69. package/template/agent/skills/rust-developer/references/rust-rules/api-from-not-into.md +0 -146
  70. package/template/agent/skills/rust-developer/references/rust-rules/api-impl-asref.md +0 -142
  71. package/template/agent/skills/rust-developer/references/rust-rules/api-impl-into.md +0 -160
  72. package/template/agent/skills/rust-developer/references/rust-rules/api-must-use.md +0 -125
  73. package/template/agent/skills/rust-developer/references/rust-rules/api-newtype-safety.md +0 -162
  74. package/template/agent/skills/rust-developer/references/rust-rules/api-non-exhaustive.md +0 -177
  75. package/template/agent/skills/rust-developer/references/rust-rules/api-parse-dont-validate.md +0 -184
  76. package/template/agent/skills/rust-developer/references/rust-rules/api-sealed-trait.md +0 -168
  77. package/template/agent/skills/rust-developer/references/rust-rules/api-serde-optional.md +0 -182
  78. package/template/agent/skills/rust-developer/references/rust-rules/api-typestate.md +0 -199
  79. package/template/agent/skills/rust-developer/references/rust-rules/async-bounded-channel.md +0 -175
  80. package/template/agent/skills/rust-developer/references/rust-rules/async-broadcast-pubsub.md +0 -185
  81. package/template/agent/skills/rust-developer/references/rust-rules/async-cancellation-token.md +0 -203
  82. package/template/agent/skills/rust-developer/references/rust-rules/async-clone-before-await.md +0 -171
  83. package/template/agent/skills/rust-developer/references/rust-rules/async-join-parallel.md +0 -158
  84. package/template/agent/skills/rust-developer/references/rust-rules/async-joinset-structured.md +0 -195
  85. package/template/agent/skills/rust-developer/references/rust-rules/async-mpsc-queue.md +0 -171
  86. package/template/agent/skills/rust-developer/references/rust-rules/async-no-lock-await.md +0 -156
  87. package/template/agent/skills/rust-developer/references/rust-rules/async-oneshot-response.md +0 -191
  88. package/template/agent/skills/rust-developer/references/rust-rules/async-select-racing.md +0 -198
  89. package/template/agent/skills/rust-developer/references/rust-rules/async-spawn-blocking.md +0 -154
  90. package/template/agent/skills/rust-developer/references/rust-rules/async-tokio-fs.md +0 -167
  91. package/template/agent/skills/rust-developer/references/rust-rules/async-tokio-runtime.md +0 -169
  92. package/template/agent/skills/rust-developer/references/rust-rules/async-try-join.md +0 -172
  93. package/template/agent/skills/rust-developer/references/rust-rules/async-watch-latest.md +0 -189
  94. package/template/agent/skills/rust-developer/references/rust-rules/doc-all-public.md +0 -113
  95. package/template/agent/skills/rust-developer/references/rust-rules/doc-cargo-metadata.md +0 -147
  96. package/template/agent/skills/rust-developer/references/rust-rules/doc-errors-section.md +0 -122
  97. package/template/agent/skills/rust-developer/references/rust-rules/doc-examples-section.md +0 -161
  98. package/template/agent/skills/rust-developer/references/rust-rules/doc-hidden-setup.md +0 -149
  99. package/template/agent/skills/rust-developer/references/rust-rules/doc-intra-links.md +0 -138
  100. package/template/agent/skills/rust-developer/references/rust-rules/doc-link-types.md +0 -169
  101. package/template/agent/skills/rust-developer/references/rust-rules/doc-module-inner.md +0 -116
  102. package/template/agent/skills/rust-developer/references/rust-rules/doc-panics-section.md +0 -128
  103. package/template/agent/skills/rust-developer/references/rust-rules/doc-question-mark.md +0 -136
  104. package/template/agent/skills/rust-developer/references/rust-rules/doc-safety-section.md +0 -131
  105. package/template/agent/skills/rust-developer/references/rust-rules/err-anyhow-app.md +0 -179
  106. package/template/agent/skills/rust-developer/references/rust-rules/err-context-chain.md +0 -144
  107. package/template/agent/skills/rust-developer/references/rust-rules/err-custom-type.md +0 -152
  108. package/template/agent/skills/rust-developer/references/rust-rules/err-doc-errors.md +0 -145
  109. package/template/agent/skills/rust-developer/references/rust-rules/err-expect-bugs-only.md +0 -133
  110. package/template/agent/skills/rust-developer/references/rust-rules/err-from-impl.md +0 -152
  111. package/template/agent/skills/rust-developer/references/rust-rules/err-lowercase-msg.md +0 -124
  112. package/template/agent/skills/rust-developer/references/rust-rules/err-no-unwrap-prod.md +0 -115
  113. package/template/agent/skills/rust-developer/references/rust-rules/err-question-mark.md +0 -151
  114. package/template/agent/skills/rust-developer/references/rust-rules/err-result-over-panic.md +0 -130
  115. package/template/agent/skills/rust-developer/references/rust-rules/err-source-chain.md +0 -155
  116. package/template/agent/skills/rust-developer/references/rust-rules/err-thiserror-lib.md +0 -171
  117. package/template/agent/skills/rust-developer/references/rust-rules/lint-cargo-metadata.md +0 -138
  118. package/template/agent/skills/rust-developer/references/rust-rules/lint-deny-correctness.md +0 -107
  119. package/template/agent/skills/rust-developer/references/rust-rules/lint-missing-docs.md +0 -154
  120. package/template/agent/skills/rust-developer/references/rust-rules/lint-pedantic-selective.md +0 -118
  121. package/template/agent/skills/rust-developer/references/rust-rules/lint-rustfmt-check.md +0 -157
  122. package/template/agent/skills/rust-developer/references/rust-rules/lint-unsafe-doc.md +0 -133
  123. package/template/agent/skills/rust-developer/references/rust-rules/lint-warn-complexity.md +0 -131
  124. package/template/agent/skills/rust-developer/references/rust-rules/lint-warn-perf.md +0 -136
  125. package/template/agent/skills/rust-developer/references/rust-rules/lint-warn-style.md +0 -135
  126. package/template/agent/skills/rust-developer/references/rust-rules/lint-warn-suspicious.md +0 -122
  127. package/template/agent/skills/rust-developer/references/rust-rules/lint-workspace-lints.md +0 -172
  128. package/template/agent/skills/rust-developer/references/rust-rules/mem-arena-allocator.md +0 -168
  129. package/template/agent/skills/rust-developer/references/rust-rules/mem-arrayvec.md +0 -142
  130. package/template/agent/skills/rust-developer/references/rust-rules/mem-assert-type-size.md +0 -168
  131. package/template/agent/skills/rust-developer/references/rust-rules/mem-avoid-format.md +0 -147
  132. package/template/agent/skills/rust-developer/references/rust-rules/mem-box-large-variant.md +0 -158
  133. package/template/agent/skills/rust-developer/references/rust-rules/mem-boxed-slice.md +0 -139
  134. package/template/agent/skills/rust-developer/references/rust-rules/mem-clone-from.md +0 -147
  135. package/template/agent/skills/rust-developer/references/rust-rules/mem-compact-string.md +0 -149
  136. package/template/agent/skills/rust-developer/references/rust-rules/mem-reuse-collections.md +0 -174
  137. package/template/agent/skills/rust-developer/references/rust-rules/mem-smaller-integers.md +0 -159
  138. package/template/agent/skills/rust-developer/references/rust-rules/mem-smallvec.md +0 -138
  139. package/template/agent/skills/rust-developer/references/rust-rules/mem-thinvec.md +0 -142
  140. package/template/agent/skills/rust-developer/references/rust-rules/mem-with-capacity.md +0 -156
  141. package/template/agent/skills/rust-developer/references/rust-rules/mem-write-over-format.md +0 -172
  142. package/template/agent/skills/rust-developer/references/rust-rules/mem-zero-copy.md +0 -164
  143. package/template/agent/skills/rust-developer/references/rust-rules/name-acronym-word.md +0 -99
  144. package/template/agent/skills/rust-developer/references/rust-rules/name-as-free.md +0 -104
  145. package/template/agent/skills/rust-developer/references/rust-rules/name-consts-screaming.md +0 -94
  146. package/template/agent/skills/rust-developer/references/rust-rules/name-crate-no-rs.md +0 -78
  147. package/template/agent/skills/rust-developer/references/rust-rules/name-funcs-snake.md +0 -76
  148. package/template/agent/skills/rust-developer/references/rust-rules/name-into-ownership.md +0 -123
  149. package/template/agent/skills/rust-developer/references/rust-rules/name-is-has-bool.md +0 -127
  150. package/template/agent/skills/rust-developer/references/rust-rules/name-iter-convention.md +0 -129
  151. package/template/agent/skills/rust-developer/references/rust-rules/name-iter-method.md +0 -131
  152. package/template/agent/skills/rust-developer/references/rust-rules/name-iter-type-match.md +0 -142
  153. package/template/agent/skills/rust-developer/references/rust-rules/name-lifetime-short.md +0 -86
  154. package/template/agent/skills/rust-developer/references/rust-rules/name-no-get-prefix.md +0 -154
  155. package/template/agent/skills/rust-developer/references/rust-rules/name-to-expensive.md +0 -118
  156. package/template/agent/skills/rust-developer/references/rust-rules/name-type-param-single.md +0 -92
  157. package/template/agent/skills/rust-developer/references/rust-rules/name-types-camel.md +0 -65
  158. package/template/agent/skills/rust-developer/references/rust-rules/name-variants-camel.md +0 -101
  159. package/template/agent/skills/rust-developer/references/rust-rules/opt-bounds-check.md +0 -161
  160. package/template/agent/skills/rust-developer/references/rust-rules/opt-cache-friendly.md +0 -187
  161. package/template/agent/skills/rust-developer/references/rust-rules/opt-codegen-units.md +0 -142
  162. package/template/agent/skills/rust-developer/references/rust-rules/opt-cold-unlikely.md +0 -152
  163. package/template/agent/skills/rust-developer/references/rust-rules/opt-inline-always-rare.md +0 -141
  164. package/template/agent/skills/rust-developer/references/rust-rules/opt-inline-never-cold.md +0 -181
  165. package/template/agent/skills/rust-developer/references/rust-rules/opt-inline-small.md +0 -160
  166. package/template/agent/skills/rust-developer/references/rust-rules/opt-likely-hint.md +0 -171
  167. package/template/agent/skills/rust-developer/references/rust-rules/opt-lto-release.md +0 -130
  168. package/template/agent/skills/rust-developer/references/rust-rules/opt-pgo-profile.md +0 -167
  169. package/template/agent/skills/rust-developer/references/rust-rules/opt-simd-portable.md +0 -144
  170. package/template/agent/skills/rust-developer/references/rust-rules/opt-target-cpu.md +0 -154
  171. package/template/agent/skills/rust-developer/references/rust-rules/own-arc-shared.md +0 -141
  172. package/template/agent/skills/rust-developer/references/rust-rules/own-borrow-over-clone.md +0 -95
  173. package/template/agent/skills/rust-developer/references/rust-rules/own-clone-explicit.md +0 -135
  174. package/template/agent/skills/rust-developer/references/rust-rules/own-copy-small.md +0 -124
  175. package/template/agent/skills/rust-developer/references/rust-rules/own-cow-conditional.md +0 -135
  176. package/template/agent/skills/rust-developer/references/rust-rules/own-lifetime-elision.md +0 -134
  177. package/template/agent/skills/rust-developer/references/rust-rules/own-move-large.md +0 -134
  178. package/template/agent/skills/rust-developer/references/rust-rules/own-mutex-interior.md +0 -105
  179. package/template/agent/skills/rust-developer/references/rust-rules/own-rc-single-thread.md +0 -65
  180. package/template/agent/skills/rust-developer/references/rust-rules/own-refcell-interior.md +0 -97
  181. package/template/agent/skills/rust-developer/references/rust-rules/own-rwlock-readers.md +0 -122
  182. package/template/agent/skills/rust-developer/references/rust-rules/own-slice-over-vec.md +0 -119
  183. package/template/agent/skills/rust-developer/references/rust-rules/perf-black-box-bench.md +0 -153
  184. package/template/agent/skills/rust-developer/references/rust-rules/perf-chain-avoid.md +0 -136
  185. package/template/agent/skills/rust-developer/references/rust-rules/perf-collect-into.md +0 -133
  186. package/template/agent/skills/rust-developer/references/rust-rules/perf-collect-once.md +0 -120
  187. package/template/agent/skills/rust-developer/references/rust-rules/perf-drain-reuse.md +0 -137
  188. package/template/agent/skills/rust-developer/references/rust-rules/perf-entry-api.md +0 -134
  189. package/template/agent/skills/rust-developer/references/rust-rules/perf-extend-batch.md +0 -150
  190. package/template/agent/skills/rust-developer/references/rust-rules/perf-iter-lazy.md +0 -123
  191. package/template/agent/skills/rust-developer/references/rust-rules/perf-iter-over-index.md +0 -113
  192. package/template/agent/skills/rust-developer/references/rust-rules/perf-profile-first.md +0 -175
  193. package/template/agent/skills/rust-developer/references/rust-rules/perf-release-profile.md +0 -149
  194. package/template/agent/skills/rust-developer/references/rust-rules/proj-bin-dir.md +0 -142
  195. package/template/agent/skills/rust-developer/references/rust-rules/proj-flat-small.md +0 -133
  196. package/template/agent/skills/rust-developer/references/rust-rules/proj-lib-main-split.md +0 -148
  197. package/template/agent/skills/rust-developer/references/rust-rules/proj-mod-by-feature.md +0 -130
  198. package/template/agent/skills/rust-developer/references/rust-rules/proj-mod-rs-dir.md +0 -120
  199. package/template/agent/skills/rust-developer/references/rust-rules/proj-prelude-module.md +0 -155
  200. package/template/agent/skills/rust-developer/references/rust-rules/proj-pub-crate-internal.md +0 -139
  201. package/template/agent/skills/rust-developer/references/rust-rules/proj-pub-super-parent.md +0 -135
  202. package/template/agent/skills/rust-developer/references/rust-rules/proj-pub-use-reexport.md +0 -162
  203. package/template/agent/skills/rust-developer/references/rust-rules/proj-workspace-deps.md +0 -186
  204. package/template/agent/skills/rust-developer/references/rust-rules/proj-workspace-large.md +0 -162
  205. package/template/agent/skills/rust-developer/references/rust-rules/test-arrange-act-assert.md +0 -160
  206. package/template/agent/skills/rust-developer/references/rust-rules/test-cfg-test-module.md +0 -151
  207. package/template/agent/skills/rust-developer/references/rust-rules/test-criterion-bench.md +0 -171
  208. package/template/agent/skills/rust-developer/references/rust-rules/test-descriptive-names.md +0 -142
  209. package/template/agent/skills/rust-developer/references/rust-rules/test-doctest-examples.md +0 -168
  210. package/template/agent/skills/rust-developer/references/rust-rules/test-fixture-raii.md +0 -151
  211. package/template/agent/skills/rust-developer/references/rust-rules/test-integration-dir.md +0 -144
  212. package/template/agent/skills/rust-developer/references/rust-rules/test-mock-traits.md +0 -189
  213. package/template/agent/skills/rust-developer/references/rust-rules/test-mockall-mocking.md +0 -226
  214. package/template/agent/skills/rust-developer/references/rust-rules/test-proptest-properties.md +0 -161
  215. package/template/agent/skills/rust-developer/references/rust-rules/test-should-panic.md +0 -130
  216. package/template/agent/skills/rust-developer/references/rust-rules/test-tokio-async.md +0 -154
  217. package/template/agent/skills/rust-developer/references/rust-rules/test-use-super.md +0 -127
  218. package/template/agent/skills/rust-developer/references/rust-rules/type-enum-states.md +0 -154
  219. package/template/agent/skills/rust-developer/references/rust-rules/type-generic-bounds.md +0 -142
  220. package/template/agent/skills/rust-developer/references/rust-rules/type-never-diverge.md +0 -146
  221. package/template/agent/skills/rust-developer/references/rust-rules/type-newtype-ids.md +0 -160
  222. package/template/agent/skills/rust-developer/references/rust-rules/type-newtype-validated.md +0 -159
  223. package/template/agent/skills/rust-developer/references/rust-rules/type-no-stringly.md +0 -144
  224. package/template/agent/skills/rust-developer/references/rust-rules/type-option-nullable.md +0 -137
  225. package/template/agent/skills/rust-developer/references/rust-rules/type-phantom-marker.md +0 -188
  226. package/template/agent/skills/rust-developer/references/rust-rules/type-repr-transparent.md +0 -143
  227. package/template/agent/skills/rust-developer/references/rust-rules/type-result-fallible.md +0 -131
  228. package/template/agent/skills/saas-architect/SKILL.md +0 -139
  229. package/template/agent/skills/security-engineer/SKILL.md +0 -133
  230. package/template/agent/skills/seo-specialist/SKILL.md +0 -130
  231. package/template/agent/skills/solo-founder-ops/SKILL.md +0 -56
@@ -1,162 +0,0 @@
1
- # api-newtype-safety
2
-
3
- > Use newtypes to prevent mixing semantically different values
4
-
5
- ## Why It Matters
6
-
7
- Raw primitives like `u64` or `String` carry no semantic meaning. A function taking `(u64, u64)` can easily be called with arguments swapped. Newtypes wrap primitives in distinct types, making the compiler catch mistakes at compile time rather than runtime.
8
-
9
- ## Bad
10
-
11
- ```rust
12
- struct User {
13
- id: u64,
14
- group_id: u64,
15
- created_at: u64, // Unix timestamp
16
- }
17
-
18
- fn add_user_to_group(user_id: u64, group_id: u64) { ... }
19
-
20
- // Bug: arguments swapped - compiles fine, fails at runtime
21
- let user = User { id: 100, group_id: 5, created_at: 1234567890 };
22
- add_user_to_group(user.group_id, user.id); // Silent bug!
23
-
24
- // Bug: wrong field used - timestamp passed as ID
25
- add_user_to_group(user.created_at, user.group_id); // Compiles fine!
26
- ```
27
-
28
- ## Good
29
-
30
- ```rust
31
- #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
32
- struct UserId(u64);
33
-
34
- #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
35
- struct GroupId(u64);
36
-
37
- #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
38
- struct Timestamp(u64);
39
-
40
- struct User {
41
- id: UserId,
42
- group_id: GroupId,
43
- created_at: Timestamp,
44
- }
45
-
46
- fn add_user_to_group(user_id: UserId, group_id: GroupId) { ... }
47
-
48
- // Compile error: expected UserId, found GroupId
49
- let user = User { ... };
50
- add_user_to_group(user.group_id, user.id); // Error!
51
-
52
- // Compile error: expected UserId, found Timestamp
53
- add_user_to_group(user.created_at, user.group_id); // Error!
54
- ```
55
-
56
- ## Derive Common Traits
57
-
58
- ```rust
59
- // Minimal: just enough for your use case
60
- #[derive(Debug, Clone, Copy)]
61
- struct MeterId(u32);
62
-
63
- // Full ID type: hashable, comparable, displayable
64
- #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
65
- struct OrderId(u64);
66
-
67
- impl std::fmt::Display for OrderId {
68
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
69
- write!(f, "ORD-{:08}", self.0)
70
- }
71
- }
72
-
73
- // With serde for serialization
74
- #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
75
- #[serde(transparent)] // Serializes as raw u64
76
- struct ProductId(u64);
77
- ```
78
-
79
- ## Constructor Patterns
80
-
81
- ```rust
82
- #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
83
- struct Email(String);
84
-
85
- impl Email {
86
- /// Creates a new Email, validating the format.
87
- pub fn new(s: &str) -> Result<Self, EmailError> {
88
- if is_valid_email(s) {
89
- Ok(Email(s.to_string()))
90
- } else {
91
- Err(EmailError::InvalidFormat)
92
- }
93
- }
94
-
95
- /// Returns the email as a string slice.
96
- pub fn as_str(&self) -> &str {
97
- &self.0
98
- }
99
- }
100
-
101
- // Usage enforces validation
102
- let email = Email::new("user@example.com")?; // Must go through validation
103
- ```
104
-
105
- ## Zero-Cost Abstraction
106
-
107
- ```rust
108
- use std::mem::size_of;
109
-
110
- #[derive(Clone, Copy)]
111
- struct Miles(f64);
112
-
113
- #[derive(Clone, Copy)]
114
- struct Kilometers(f64);
115
-
116
- // Same size as raw f64
117
- assert_eq!(size_of::<Miles>(), size_of::<f64>());
118
- assert_eq!(size_of::<Kilometers>(), size_of::<f64>());
119
-
120
- // But can't accidentally mix them
121
- fn drive(distance: Miles) { ... }
122
-
123
- let km = Kilometers(100.0);
124
- drive(km); // Error: expected Miles, found Kilometers
125
-
126
- // Explicit conversion
127
- impl From<Kilometers> for Miles {
128
- fn from(km: Kilometers) -> Self {
129
- Miles(km.0 * 0.621371)
130
- }
131
- }
132
-
133
- drive(km.into()); // Explicit, visible conversion
134
- ```
135
-
136
- ## When Newtypes Help Most
137
-
138
- ```rust
139
- // ✅ IDs that could be confused
140
- fn transfer(from: AccountId, to: AccountId, amount: Money) { ... }
141
-
142
- // ✅ Units that shouldn't mix
143
- struct Celsius(f64);
144
- struct Fahrenheit(f64);
145
-
146
- // ✅ Validated strings
147
- struct Username(String); // Validated alphanumeric
148
- struct Password(String); // Never logged
149
-
150
- // ✅ Different meanings of same type
151
- struct Milliseconds(u64);
152
- struct Seconds(u64);
153
-
154
- // ❌ Overkill: single use, no confusion possible
155
- struct X(i32); // Just use i32
156
- ```
157
-
158
- ## See Also
159
-
160
- - [type-newtype-ids](./type-newtype-ids.md) - Newtype pattern for IDs
161
- - [api-parse-dont-validate](./api-parse-dont-validate.md) - Type-driven validation
162
- - [own-copy-small](./own-copy-small.md) - Making newtypes Copy
@@ -1,177 +0,0 @@
1
- # api-non-exhaustive
2
-
3
- > Use `#[non_exhaustive]` on public enums and structs for forward compatibility
4
-
5
- ## Why It Matters
6
-
7
- Adding a variant to a public enum or a field to a public struct is normally a breaking change—downstream code may match exhaustively or use struct literal syntax. `#[non_exhaustive]` forces external code to use wildcards in matches and constructors, allowing you to add variants/fields in minor versions without breaking callers.
8
-
9
- ## Bad
10
-
11
- ```rust
12
- // Public enum - adding variant breaks downstream matches
13
- pub enum ErrorKind {
14
- NotFound,
15
- PermissionDenied,
16
- TimedOut,
17
- }
18
-
19
- // Downstream code
20
- match error.kind() {
21
- ErrorKind::NotFound => ...,
22
- ErrorKind::PermissionDenied => ...,
23
- ErrorKind::TimedOut => ...,
24
- // No wildcard - will break when you add ErrorKind::Interrupted
25
- }
26
-
27
- // Public struct - adding field breaks downstream construction
28
- pub struct Config {
29
- pub name: String,
30
- pub value: i32,
31
- }
32
-
33
- // Downstream code
34
- let config = Config { name: "test".into(), value: 42 };
35
- // Will break when you add `pub enabled: bool`
36
- ```
37
-
38
- ## Good
39
-
40
- ```rust
41
- // Can add variants in minor versions
42
- #[non_exhaustive]
43
- pub enum ErrorKind {
44
- NotFound,
45
- PermissionDenied,
46
- TimedOut,
47
- // Future: can add Interrupted here without breaking changes
48
- }
49
-
50
- // Downstream code MUST have wildcard
51
- match error.kind() {
52
- ErrorKind::NotFound => ...,
53
- ErrorKind::PermissionDenied => ...,
54
- ErrorKind::TimedOut => ...,
55
- _ => ..., // Required by non_exhaustive
56
- }
57
-
58
- // Can add fields in minor versions
59
- #[non_exhaustive]
60
- pub struct Config {
61
- pub name: String,
62
- pub value: i32,
63
- }
64
-
65
- // Downstream CANNOT use struct literal syntax
66
- // let config = Config { name: "test".into(), value: 42 }; // Error!
67
-
68
- // Must use constructor
69
- impl Config {
70
- pub fn new(name: impl Into<String>, value: i32) -> Self {
71
- Config { name: name.into(), value }
72
- }
73
- }
74
- ```
75
-
76
- ## How It Works
77
-
78
- ```rust
79
- #[non_exhaustive]
80
- pub enum Status {
81
- Active,
82
- Inactive,
83
- }
84
-
85
- // Inside your crate: exhaustive match is allowed
86
- fn internal(s: Status) {
87
- match s {
88
- Status::Active => {},
89
- Status::Inactive => {},
90
- // No wildcard needed inside defining crate
91
- }
92
- }
93
-
94
- // Outside your crate: wildcard required
95
- fn external(s: my_crate::Status) {
96
- match s {
97
- my_crate::Status::Active => {},
98
- my_crate::Status::Inactive => {},
99
- _ => {}, // REQUIRED
100
- }
101
- }
102
- ```
103
-
104
- ## Struct Usage
105
-
106
- ```rust
107
- #[non_exhaustive]
108
- pub struct Point {
109
- pub x: f64,
110
- pub y: f64,
111
- }
112
-
113
- impl Point {
114
- // Provide constructor
115
- pub fn new(x: f64, y: f64) -> Self {
116
- Point { x, y }
117
- }
118
- }
119
-
120
- // External code can read fields but not construct with literals
121
- fn external(p: Point) {
122
- println!("x: {}, y: {}", p.x, p.y); // Reading is fine
123
-
124
- // let p2 = Point { x: 1.0, y: 2.0 }; // Error!
125
- let p2 = Point::new(1.0, 2.0); // Must use constructor
126
- }
127
- ```
128
-
129
- ## Non-Exhaustive Variants
130
-
131
- ```rust
132
- pub enum Message {
133
- // Specific variant is non-exhaustive
134
- #[non_exhaustive]
135
- Error { code: u32, message: String },
136
-
137
- Ok(Data),
138
- }
139
-
140
- // Can destructure Ok normally
141
- // But Error requires `..` to handle future fields
142
- match msg {
143
- Message::Ok(data) => {},
144
- Message::Error { code, message, .. } => {}, // `..` required
145
- }
146
- ```
147
-
148
- ## When to Use
149
-
150
- ```rust
151
- // ✅ Use for public API types that may evolve
152
- #[non_exhaustive]
153
- pub enum ApiError { ... }
154
-
155
- #[non_exhaustive]
156
- pub struct Options { ... }
157
-
158
- // ✅ Use for error types
159
- #[non_exhaustive]
160
- pub enum MyError { ... }
161
-
162
- // ❌ Don't use for internal types
163
- enum InternalState { ... } // Not public, no concern
164
-
165
- // ❌ Don't use for stable, complete types
166
- pub enum Ordering { // Less, Equal, Greater is complete
167
- Less,
168
- Equal,
169
- Greater,
170
- }
171
- ```
172
-
173
- ## See Also
174
-
175
- - [api-sealed-trait](./api-sealed-trait.md) - Controlling trait implementations
176
- - [err-custom-type](./err-custom-type.md) - Error type design
177
- - [api-builder-pattern](./api-builder-pattern.md) - Alternative to struct literals
@@ -1,184 +0,0 @@
1
- # api-parse-dont-validate
2
-
3
- > Parse into validated types at boundaries
4
-
5
- ## Why It Matters
6
-
7
- Instead of validating data and hoping you remember to check everywhere, parse it into a type that can only be constructed from valid data. The type system then guarantees validity - you can't forget to validate because invalid states are unrepresentable.
8
-
9
- ## Bad
10
-
11
- ```rust
12
- // Validation scattered throughout codebase
13
- fn send_email(email: &str) -> Result<(), Error> {
14
- // Did someone validate this already? Who knows!
15
- if !is_valid_email(email) {
16
- return Err(Error::InvalidEmail);
17
- }
18
- // Send email...
19
- }
20
-
21
- fn add_to_mailing_list(email: &str) -> Result<(), Error> {
22
- // Duplicate validation, or did we forget?
23
- if !is_valid_email(email) {
24
- return Err(Error::InvalidEmail);
25
- }
26
- // Add to list...
27
- }
28
-
29
- // Easy to forget validation
30
- fn process_user_email(email: &str) {
31
- // Oops, no validation!
32
- database.store_email(email);
33
- }
34
- ```
35
-
36
- ## Good
37
-
38
- ```rust
39
- /// A validated email address.
40
- /// Can only be constructed via `Email::parse()`.
41
- #[derive(Debug, Clone, PartialEq, Eq, Hash)]
42
- pub struct Email(String);
43
-
44
- impl Email {
45
- /// Parses and validates an email address.
46
- pub fn parse(s: impl Into<String>) -> Result<Self, EmailError> {
47
- let s = s.into();
48
- if Self::is_valid(&s) {
49
- Ok(Email(s))
50
- } else {
51
- Err(EmailError::Invalid)
52
- }
53
- }
54
-
55
- fn is_valid(s: &str) -> bool {
56
- s.contains('@') && s.len() > 3 // Simplified
57
- }
58
-
59
- pub fn as_str(&self) -> &str {
60
- &self.0
61
- }
62
- }
63
-
64
- // Now functions can accept Email - guaranteed valid!
65
- fn send_email(email: &Email) -> Result<(), Error> {
66
- // No validation needed - Email is always valid
67
- smtp_send(email.as_str())
68
- }
69
-
70
- fn add_to_mailing_list(email: Email) {
71
- // No validation needed
72
- list.push(email);
73
- }
74
- ```
75
-
76
- ## More Examples
77
-
78
- ```rust
79
- // Port number (1-65535)
80
- pub struct Port(u16);
81
-
82
- impl Port {
83
- pub fn new(n: u16) -> Option<Self> {
84
- if n > 0 { Some(Port(n)) } else { None }
85
- }
86
-
87
- pub fn get(&self) -> u16 {
88
- self.0
89
- }
90
- }
91
-
92
- // Non-empty string
93
- pub struct NonEmptyString(String);
94
-
95
- impl NonEmptyString {
96
- pub fn new(s: impl Into<String>) -> Option<Self> {
97
- let s = s.into();
98
- if s.is_empty() { None } else { Some(Self(s)) }
99
- }
100
- }
101
-
102
- // Positive integer
103
- pub struct PositiveI32(i32);
104
-
105
- impl PositiveI32 {
106
- pub fn new(n: i32) -> Option<Self> {
107
- if n > 0 { Some(Self(n)) } else { None }
108
- }
109
- }
110
-
111
- // Bounded value
112
- pub struct Percentage(u8);
113
-
114
- impl Percentage {
115
- pub fn new(n: u8) -> Option<Self> {
116
- if n <= 100 { Some(Self(n)) } else { None }
117
- }
118
- }
119
- ```
120
-
121
- ## Parsing at Boundaries
122
-
123
- ```rust
124
- // Parse at the system boundary (API, CLI, config file)
125
- fn handle_request(raw: RawRequest) -> Result<Response, Error> {
126
- // Parse ALL inputs upfront
127
- let email = Email::parse(&raw.email)?;
128
- let age = Age::parse(raw.age)?;
129
- let username = Username::parse(&raw.username)?;
130
-
131
- // Now work with validated types
132
- process_user(email, age, username)
133
- }
134
-
135
- fn process_user(email: Email, age: Age, username: Username) {
136
- // All inputs guaranteed valid - no checks needed
137
- }
138
- ```
139
-
140
- ## Evidence from sqlx
141
-
142
- ```rust
143
- // sqlx parses SQL at compile time, ensuring query validity
144
- // https://github.com/launchbadge/sqlx/blob/master/src/macros/mod.rs
145
-
146
- // The query! macro parses and validates SQL
147
- let user = sqlx::query!("SELECT * FROM users WHERE id = ?", id)
148
- .fetch_one(&pool)
149
- .await?;
150
-
151
- // If SQL is invalid, compilation fails - invalid state unrepresentable
152
- ```
153
-
154
- ## Combining with Display
155
-
156
- ```rust
157
- use std::fmt;
158
-
159
- pub struct Email(String);
160
-
161
- impl Email {
162
- pub fn parse(s: &str) -> Result<Self, EmailError> { ... }
163
- }
164
-
165
- // Implement Display for easy printing
166
- impl fmt::Display for Email {
167
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
168
- write!(f, "{}", self.0)
169
- }
170
- }
171
-
172
- // Implement AsRef for easy borrowing
173
- impl AsRef<str> for Email {
174
- fn as_ref(&self) -> &str {
175
- &self.0
176
- }
177
- }
178
- ```
179
-
180
- ## See Also
181
-
182
- - [api-newtype-safety](api-newtype-safety.md) - Use newtypes for type safety
183
- - [type-newtype-validated](type-newtype-validated.md) - Newtypes for validated data
184
- - [api-typestate](api-typestate.md) - Compile-time state machines
@@ -1,168 +0,0 @@
1
- # api-sealed-trait
2
-
3
- > Use sealed traits to prevent external implementations while allowing use
4
-
5
- ## Why It Matters
6
-
7
- Public traits can be implemented by anyone, which may be undesirable when you need to guarantee behavior or add methods in future versions. A sealed trait can be used by external code but not implemented by it, giving you control over implementations while maintaining a usable API.
8
-
9
- ## Bad
10
-
11
- ```rust
12
- // Anyone can implement this trait
13
- pub trait DatabaseDriver {
14
- fn connect(&self, url: &str) -> Connection;
15
- fn execute(&self, query: &str) -> Result<Rows, Error>;
16
- }
17
-
18
- // External crate implements it incorrectly
19
- impl DatabaseDriver for MyBadDriver {
20
- fn connect(&self, url: &str) -> Connection {
21
- // Buggy implementation that doesn't handle errors
22
- unsafe { force_connect(url) }
23
- }
24
- }
25
-
26
- // Later, you want to add a required method - BREAKING CHANGE
27
- pub trait DatabaseDriver {
28
- fn connect(&self, url: &str) -> Connection;
29
- fn execute(&self, query: &str) -> Result<Rows, Error>;
30
- fn transaction(&self) -> Transaction; // External impls now broken!
31
- }
32
- ```
33
-
34
- ## Good
35
-
36
- ```rust
37
- // Create a private module with a private trait
38
- mod private {
39
- pub trait Sealed {}
40
- }
41
-
42
- // Public trait requires the private trait
43
- pub trait DatabaseDriver: private::Sealed {
44
- fn connect(&self, url: &str) -> Connection;
45
- fn execute(&self, query: &str) -> Result<Rows, Error>;
46
- }
47
-
48
- // Only your crate can implement Sealed, thus DatabaseDriver
49
- pub struct PostgresDriver;
50
- impl private::Sealed for PostgresDriver {}
51
- impl DatabaseDriver for PostgresDriver {
52
- fn connect(&self, url: &str) -> Connection { ... }
53
- fn execute(&self, query: &str) -> Result<Rows, Error> { ... }
54
- }
55
-
56
- pub struct MySqlDriver;
57
- impl private::Sealed for MySqlDriver {}
58
- impl DatabaseDriver for MySqlDriver {
59
- fn connect(&self, url: &str) -> Connection { ... }
60
- fn execute(&self, query: &str) -> Result<Rows, Error> { ... }
61
- }
62
-
63
- // External crate cannot implement - private::Sealed is not accessible
64
- // impl DatabaseDriver for ExternalDriver { } // Error!
65
-
66
- // But external code CAN use the trait
67
- fn use_driver(driver: &impl DatabaseDriver) {
68
- let conn = driver.connect("postgres://localhost");
69
- }
70
- ```
71
-
72
- ## Full Pattern
73
-
74
- ```rust
75
- pub mod db {
76
- mod private {
77
- pub trait Sealed {}
78
- }
79
-
80
- /// Database driver trait.
81
- ///
82
- /// This trait is sealed and cannot be implemented outside this crate.
83
- pub trait Driver: private::Sealed {
84
- /// Connects to the database.
85
- fn connect(&self, url: &str) -> Result<Connection, Error>;
86
-
87
- /// Executes a query.
88
- fn execute(&self, sql: &str) -> Result<Rows, Error>;
89
- }
90
-
91
- pub struct Postgres;
92
- impl private::Sealed for Postgres {}
93
- impl Driver for Postgres { ... }
94
-
95
- pub struct Sqlite;
96
- impl private::Sealed for Sqlite {}
97
- impl Driver for Sqlite { ... }
98
- }
99
-
100
- // Usage works fine
101
- use db::{Driver, Postgres};
102
-
103
- fn query(driver: &impl Driver) {
104
- driver.execute("SELECT 1")?;
105
- }
106
-
107
- query(&Postgres);
108
- ```
109
-
110
- ## Benefits of Sealing
111
-
112
- ```rust
113
- // 1. Add methods without breaking changes
114
- pub trait Format: private::Sealed {
115
- fn format(&self) -> String;
116
-
117
- // Added later - not breaking because no external impls exist
118
- fn format_pretty(&self) -> String {
119
- self.format() // Default implementation
120
- }
121
- }
122
-
123
- // 2. Guarantee invariants
124
- pub trait SafeBuffer: private::Sealed {
125
- // You control all implementations, so you know they're all correct
126
- fn get(&self, index: usize) -> Option<&u8>;
127
- }
128
-
129
- // 3. Use as marker traits
130
- pub trait ValidConfig: private::Sealed {}
131
- // Only validated configs implement this
132
- ```
133
-
134
- ## Partially Sealed
135
-
136
- ```rust
137
- // Allow implementing some methods but not all
138
- mod private {
139
- pub trait SealedCore {}
140
- }
141
-
142
- pub trait Plugin: private::SealedCore {
143
- // Sealed - only we implement
144
- fn initialize(&self);
145
- fn shutdown(&self);
146
-
147
- // Open - users can override
148
- fn name(&self) -> &str { "unnamed" }
149
- }
150
-
151
- // Only we can add new required sealed methods
152
- // Users can customize open methods
153
- ```
154
-
155
- ## When to Seal
156
-
157
- | Seal When | Don't Seal When |
158
- |-----------|-----------------|
159
- | API stability is critical | You want extension points |
160
- | Implementation correctness is hard | Users need custom implementations |
161
- | You'll add methods later | Trait is simple and stable |
162
- | Safety invariants required | Standard patterns (Iterator, etc.) |
163
-
164
- ## See Also
165
-
166
- - [api-non-exhaustive](./api-non-exhaustive.md) - Related pattern for enums/structs
167
- - [api-extension-trait](./api-extension-trait.md) - Adding methods to external types
168
- - [api-typestate](./api-typestate.md) - Compile-time state guarantees