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,168 @@
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
@@ -0,0 +1,182 @@
1
+ # api-serde-optional
2
+
3
+ > Make serde a feature flag, not a hard dependency for library crates
4
+
5
+ ## Why It Matters
6
+
7
+ Not all users of your library need serialization. Making serde a required dependency adds compile time and binary size for everyone. Feature flags let users opt-in to serde support only when needed, following Rust's philosophy of zero-cost abstractions and minimal dependencies.
8
+
9
+ ## Bad
10
+
11
+ ```rust
12
+ // Cargo.toml
13
+ [dependencies]
14
+ serde = { version = "1.0", features = ["derive"] }
15
+
16
+ // lib.rs
17
+ use serde::{Serialize, Deserialize};
18
+
19
+ // Every user pays for serde, even if they don't need it
20
+ #[derive(Serialize, Deserialize)]
21
+ pub struct Config {
22
+ pub name: String,
23
+ pub value: i32,
24
+ }
25
+ ```
26
+
27
+ ## Good
28
+
29
+ ```rust
30
+ // Cargo.toml
31
+ [dependencies]
32
+ serde = { version = "1.0", features = ["derive"], optional = true }
33
+
34
+ [features]
35
+ default = []
36
+ serde = ["dep:serde"]
37
+
38
+ // lib.rs
39
+ #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
40
+ pub struct Config {
41
+ pub name: String,
42
+ pub value: i32,
43
+ }
44
+
45
+ // Users opt-in:
46
+ // my_crate = { version = "1.0", features = ["serde"] }
47
+ ```
48
+
49
+ ## Macro Pattern
50
+
51
+ ```rust
52
+ // Reusable macro for serde derives
53
+ #[cfg(feature = "serde")]
54
+ macro_rules! impl_serde {
55
+ ($($t:ty),*) => {
56
+ $(
57
+ impl serde::Serialize for $t {
58
+ // ...
59
+ }
60
+ impl<'de> serde::Deserialize<'de> for $t {
61
+ // ...
62
+ }
63
+ )*
64
+ };
65
+ }
66
+
67
+ #[cfg(not(feature = "serde"))]
68
+ macro_rules! impl_serde {
69
+ ($($t:ty),*) => {};
70
+ }
71
+
72
+ // Or use cfg_attr for derived impls
73
+ #[derive(Debug, Clone)]
74
+ #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
75
+ pub struct Point {
76
+ pub x: f64,
77
+ pub y: f64,
78
+ }
79
+ ```
80
+
81
+ ## Feature Documentation
82
+
83
+ ```rust
84
+ // lib.rs
85
+
86
+ //! # Features
87
+ //!
88
+ //! - `serde`: Enables `Serialize` and `Deserialize` implementations for all types.
89
+ //!
90
+ //! # Example with serde
91
+ //!
92
+ //! ```toml
93
+ //! [dependencies]
94
+ //! my_crate = { version = "1.0", features = ["serde"] }
95
+ //! ```
96
+
97
+ #![cfg_attr(docsrs, feature(doc_cfg))]
98
+
99
+ /// A configuration type.
100
+ ///
101
+ /// When the `serde` feature is enabled, this type implements
102
+ /// `Serialize` and `Deserialize`.
103
+ #[derive(Debug, Clone)]
104
+ #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
105
+ #[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
106
+ pub struct Config {
107
+ pub name: String,
108
+ }
109
+ ```
110
+
111
+ ## Multiple Optional Dependencies
112
+
113
+ ```rust
114
+ // Cargo.toml
115
+ [dependencies]
116
+ serde = { version = "1.0", features = ["derive"], optional = true }
117
+ rkyv = { version = "0.7", optional = true }
118
+ borsh = { version = "0.10", optional = true }
119
+
120
+ [features]
121
+ default = []
122
+ serde = ["dep:serde"]
123
+ rkyv = ["dep:rkyv"]
124
+ borsh = ["dep:borsh"]
125
+
126
+ // lib.rs
127
+ #[derive(Debug, Clone)]
128
+ #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
129
+ #[cfg_attr(feature = "rkyv", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
130
+ #[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize, borsh::BorshDeserialize))]
131
+ pub struct Message {
132
+ pub id: u64,
133
+ pub content: String,
134
+ }
135
+ ```
136
+
137
+ ## Testing with Features
138
+
139
+ ```bash
140
+ # Test without serde
141
+ cargo test
142
+
143
+ # Test with serde
144
+ cargo test --features serde
145
+
146
+ # Test all feature combinations
147
+ cargo test --all-features
148
+ ```
149
+
150
+ ```rust
151
+ // Test serde round-trip when feature enabled
152
+ #[cfg(feature = "serde")]
153
+ #[test]
154
+ fn test_serde_roundtrip() {
155
+ let config = Config { name: "test".into() };
156
+ let json = serde_json::to_string(&config).unwrap();
157
+ let parsed: Config = serde_json::from_str(&json).unwrap();
158
+ assert_eq!(config, parsed);
159
+ }
160
+ ```
161
+
162
+ ## When to Make Serde Required
163
+
164
+ ```rust
165
+ // ✅ Required: Library is about serialization
166
+ // (e.g., json-schema, config-file parser)
167
+ [dependencies]
168
+ serde = "1.0"
169
+
170
+ // ✅ Required: Domain heavily uses serde
171
+ // (e.g., API client, data format library)
172
+
173
+ // ❌ Optional: General-purpose utility library
174
+ // ❌ Optional: Math/algorithm library
175
+ // ❌ Optional: Most libraries!
176
+ ```
177
+
178
+ ## See Also
179
+
180
+ - [proj-lib-main-split](./proj-lib-main-split.md) - Library structure
181
+ - [api-common-traits](./api-common-traits.md) - Core trait implementations
182
+ - [lint-deny-correctness](./lint-deny-correctness.md) - Feature testing
@@ -0,0 +1,199 @@
1
+ # api-typestate
2
+
3
+ > Use typestate pattern to encode state machine invariants in the type system
4
+
5
+ ## Why It Matters
6
+
7
+ State machines with runtime state checks ("are we connected?", "is the transaction started?") can have invalid transitions. The typestate pattern uses different types for each state, making invalid state transitions compile errors. The compiler enforces your state machine.
8
+
9
+ ## Bad
10
+
11
+ ```rust
12
+ struct Connection {
13
+ state: ConnectionState,
14
+ socket: Option<TcpStream>,
15
+ }
16
+
17
+ enum ConnectionState {
18
+ Disconnected,
19
+ Connected,
20
+ Authenticated,
21
+ }
22
+
23
+ impl Connection {
24
+ fn send(&mut self, data: &[u8]) -> Result<(), Error> {
25
+ // Runtime check - can fail if called in wrong state
26
+ if self.state != ConnectionState::Authenticated {
27
+ return Err(Error::NotAuthenticated);
28
+ }
29
+ self.socket.as_mut().unwrap().write_all(data)?;
30
+ Ok(())
31
+ }
32
+
33
+ fn authenticate(&mut self, password: &str) -> Result<(), Error> {
34
+ // Runtime check - can fail
35
+ if self.state != ConnectionState::Connected {
36
+ return Err(Error::NotConnected);
37
+ }
38
+ // ...
39
+ }
40
+ }
41
+
42
+ // Bug: forgot to authenticate
43
+ let mut conn = Connection::new();
44
+ conn.connect()?;
45
+ conn.send(b"data")?; // Runtime error: NotAuthenticated
46
+ ```
47
+
48
+ ## Good
49
+
50
+ ```rust
51
+ // Different types for each state
52
+ struct Disconnected;
53
+ struct Connected { socket: TcpStream }
54
+ struct Authenticated { socket: TcpStream, session: Session }
55
+
56
+ struct Connection<State> {
57
+ state: State,
58
+ }
59
+
60
+ impl Connection<Disconnected> {
61
+ fn new() -> Self {
62
+ Connection { state: Disconnected }
63
+ }
64
+
65
+ fn connect(self, addr: &str) -> Result<Connection<Connected>, Error> {
66
+ let socket = TcpStream::connect(addr)?;
67
+ Ok(Connection { state: Connected { socket } })
68
+ }
69
+ }
70
+
71
+ impl Connection<Connected> {
72
+ fn authenticate(self, password: &str) -> Result<Connection<Authenticated>, Error> {
73
+ let session = do_auth(&self.state.socket, password)?;
74
+ Ok(Connection {
75
+ state: Authenticated { socket: self.state.socket, session }
76
+ })
77
+ }
78
+ }
79
+
80
+ impl Connection<Authenticated> {
81
+ fn send(&mut self, data: &[u8]) -> Result<(), Error> {
82
+ // No runtime check needed - type guarantees we're authenticated
83
+ self.state.socket.write_all(data)?;
84
+ Ok(())
85
+ }
86
+ }
87
+
88
+ // Bug: forgot to authenticate
89
+ let conn = Connection::new();
90
+ let conn = conn.connect("server:8080")?;
91
+ conn.send(b"data"); // Compile error! send() not available on Connection<Connected>
92
+
93
+ // Correct usage
94
+ let conn = Connection::new();
95
+ let conn = conn.connect("server:8080")?;
96
+ let mut conn = conn.authenticate("secret")?;
97
+ conn.send(b"data")?; // Works - type is Connection<Authenticated>
98
+ ```
99
+
100
+ ## Builder Typestate
101
+
102
+ ```rust
103
+ // Enforce required fields via typestate
104
+ struct BuilderNoUrl;
105
+ struct BuilderWithUrl { url: String }
106
+
107
+ struct RequestBuilder<State> {
108
+ state: State,
109
+ timeout: Option<Duration>,
110
+ }
111
+
112
+ impl RequestBuilder<BuilderNoUrl> {
113
+ fn new() -> Self {
114
+ RequestBuilder {
115
+ state: BuilderNoUrl,
116
+ timeout: None,
117
+ }
118
+ }
119
+
120
+ fn url(self, url: &str) -> RequestBuilder<BuilderWithUrl> {
121
+ RequestBuilder {
122
+ state: BuilderWithUrl { url: url.to_string() },
123
+ timeout: self.timeout,
124
+ }
125
+ }
126
+ }
127
+
128
+ impl RequestBuilder<BuilderWithUrl> {
129
+ fn timeout(mut self, t: Duration) -> Self {
130
+ self.timeout = Some(t);
131
+ self
132
+ }
133
+
134
+ // Only available once URL is set
135
+ fn build(self) -> Request {
136
+ Request {
137
+ url: self.state.url,
138
+ timeout: self.timeout,
139
+ }
140
+ }
141
+ }
142
+
143
+ // Compile error: build() not available
144
+ let bad = RequestBuilder::new().build();
145
+
146
+ // Correct: must set URL first
147
+ let good = RequestBuilder::new()
148
+ .url("https://example.com")
149
+ .timeout(Duration::from_secs(30))
150
+ .build();
151
+ ```
152
+
153
+ ## Transaction Example
154
+
155
+ ```rust
156
+ struct NotStarted;
157
+ struct InProgress { tx_id: u64 }
158
+ struct Committed;
159
+
160
+ struct Transaction<State> {
161
+ conn: Connection,
162
+ state: State,
163
+ }
164
+
165
+ impl Transaction<NotStarted> {
166
+ fn begin(conn: Connection) -> Result<Transaction<InProgress>, Error> {
167
+ let tx_id = conn.execute("BEGIN")?;
168
+ Ok(Transaction {
169
+ conn,
170
+ state: InProgress { tx_id },
171
+ })
172
+ }
173
+ }
174
+
175
+ impl Transaction<InProgress> {
176
+ fn execute(&mut self, sql: &str) -> Result<(), Error> {
177
+ self.conn.execute(sql)
178
+ }
179
+
180
+ fn commit(self) -> Result<Transaction<Committed>, Error> {
181
+ self.conn.execute("COMMIT")?;
182
+ Ok(Transaction {
183
+ conn: self.conn,
184
+ state: Committed,
185
+ })
186
+ }
187
+
188
+ fn rollback(self) -> Connection {
189
+ let _ = self.conn.execute("ROLLBACK");
190
+ self.conn
191
+ }
192
+ }
193
+ ```
194
+
195
+ ## See Also
196
+
197
+ - [api-builder-pattern](./api-builder-pattern.md) - Basic builder pattern
198
+ - [api-parse-dont-validate](./api-parse-dont-validate.md) - Type-driven invariants
199
+ - [api-sealed-trait](./api-sealed-trait.md) - Restricting trait implementations