agy-superpowers 5.2.2 → 5.2.3

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 (220) hide show
  1. package/README.md +47 -150
  2. package/package.json +1 -1
  3. package/template/agent/rules/scratch-scripts.md +37 -0
  4. package/template/agent/rules/superpowers.md +4 -51
  5. package/template/agent/skills/ai-integrated-product/SKILL.md +0 -57
  6. package/template/agent/skills/analytics-setup/SKILL.md +0 -51
  7. package/template/agent/skills/api-design/SKILL.md +0 -193
  8. package/template/agent/skills/app-store-optimizer/SKILL.md +0 -127
  9. package/template/agent/skills/auth-and-identity/SKILL.md +0 -167
  10. package/template/agent/skills/backend-developer/SKILL.md +0 -148
  11. package/template/agent/skills/bootstrapper-finance/SKILL.md +0 -55
  12. package/template/agent/skills/chrome-extension-developer/SKILL.md +0 -53
  13. package/template/agent/skills/community-manager/SKILL.md +0 -115
  14. package/template/agent/skills/content-marketer/SKILL.md +0 -111
  15. package/template/agent/skills/conversion-optimizer/SKILL.md +0 -142
  16. package/template/agent/skills/cto-architect/SKILL.md +0 -133
  17. package/template/agent/skills/customer-success-manager/SKILL.md +0 -126
  18. package/template/agent/skills/data-analyst/SKILL.md +0 -147
  19. package/template/agent/skills/devops-engineer/SKILL.md +0 -117
  20. package/template/agent/skills/email-infrastructure/SKILL.md +0 -164
  21. package/template/agent/skills/game-design/SKILL.md +0 -194
  22. package/template/agent/skills/game-developer/SKILL.md +0 -175
  23. package/template/agent/skills/growth-hacker/SKILL.md +0 -122
  24. package/template/agent/skills/idea-validator/SKILL.md +0 -55
  25. package/template/agent/skills/indie-legal/SKILL.md +0 -53
  26. package/template/agent/skills/influencer-marketer/SKILL.md +0 -141
  27. package/template/agent/skills/landing-page-builder/SKILL.md +0 -59
  28. package/template/agent/skills/launch-strategist/SKILL.md +0 -62
  29. package/template/agent/skills/market-researcher/SKILL.md +0 -53
  30. package/template/agent/skills/micro-saas-builder/SKILL.md +0 -56
  31. package/template/agent/skills/monetization-strategist/SKILL.md +0 -119
  32. package/template/agent/skills/paid-acquisition-specialist/SKILL.md +0 -119
  33. package/template/agent/skills/pricing-psychologist/SKILL.md +0 -58
  34. package/template/agent/skills/real-time-features/SKILL.md +0 -194
  35. package/template/agent/skills/retention-specialist/SKILL.md +0 -123
  36. package/template/agent/skills/rust-developer/SKILL.md +0 -281
  37. package/template/agent/skills/rust-developer/references/rust-rules/_sections.md +0 -231
  38. package/template/agent/skills/rust-developer/references/rust-rules/anti-clone-excessive.md +0 -124
  39. package/template/agent/skills/rust-developer/references/rust-rules/anti-collect-intermediate.md +0 -131
  40. package/template/agent/skills/rust-developer/references/rust-rules/anti-empty-catch.md +0 -132
  41. package/template/agent/skills/rust-developer/references/rust-rules/anti-expect-lazy.md +0 -95
  42. package/template/agent/skills/rust-developer/references/rust-rules/anti-format-hot-path.md +0 -141
  43. package/template/agent/skills/rust-developer/references/rust-rules/anti-index-over-iter.md +0 -125
  44. package/template/agent/skills/rust-developer/references/rust-rules/anti-lock-across-await.md +0 -127
  45. package/template/agent/skills/rust-developer/references/rust-rules/anti-over-abstraction.md +0 -120
  46. package/template/agent/skills/rust-developer/references/rust-rules/anti-panic-expected.md +0 -131
  47. package/template/agent/skills/rust-developer/references/rust-rules/anti-premature-optimize.md +0 -156
  48. package/template/agent/skills/rust-developer/references/rust-rules/anti-string-for-str.md +0 -122
  49. package/template/agent/skills/rust-developer/references/rust-rules/anti-stringly-typed.md +0 -167
  50. package/template/agent/skills/rust-developer/references/rust-rules/anti-type-erasure.md +0 -134
  51. package/template/agent/skills/rust-developer/references/rust-rules/anti-unwrap-abuse.md +0 -143
  52. package/template/agent/skills/rust-developer/references/rust-rules/anti-vec-for-slice.md +0 -121
  53. package/template/agent/skills/rust-developer/references/rust-rules/api-builder-must-use.md +0 -143
  54. package/template/agent/skills/rust-developer/references/rust-rules/api-builder-pattern.md +0 -187
  55. package/template/agent/skills/rust-developer/references/rust-rules/api-common-traits.md +0 -165
  56. package/template/agent/skills/rust-developer/references/rust-rules/api-default-impl.md +0 -177
  57. package/template/agent/skills/rust-developer/references/rust-rules/api-extension-trait.md +0 -163
  58. package/template/agent/skills/rust-developer/references/rust-rules/api-from-not-into.md +0 -146
  59. package/template/agent/skills/rust-developer/references/rust-rules/api-impl-asref.md +0 -142
  60. package/template/agent/skills/rust-developer/references/rust-rules/api-impl-into.md +0 -160
  61. package/template/agent/skills/rust-developer/references/rust-rules/api-must-use.md +0 -125
  62. package/template/agent/skills/rust-developer/references/rust-rules/api-newtype-safety.md +0 -162
  63. package/template/agent/skills/rust-developer/references/rust-rules/api-non-exhaustive.md +0 -177
  64. package/template/agent/skills/rust-developer/references/rust-rules/api-parse-dont-validate.md +0 -184
  65. package/template/agent/skills/rust-developer/references/rust-rules/api-sealed-trait.md +0 -168
  66. package/template/agent/skills/rust-developer/references/rust-rules/api-serde-optional.md +0 -182
  67. package/template/agent/skills/rust-developer/references/rust-rules/api-typestate.md +0 -199
  68. package/template/agent/skills/rust-developer/references/rust-rules/async-bounded-channel.md +0 -175
  69. package/template/agent/skills/rust-developer/references/rust-rules/async-broadcast-pubsub.md +0 -185
  70. package/template/agent/skills/rust-developer/references/rust-rules/async-cancellation-token.md +0 -203
  71. package/template/agent/skills/rust-developer/references/rust-rules/async-clone-before-await.md +0 -171
  72. package/template/agent/skills/rust-developer/references/rust-rules/async-join-parallel.md +0 -158
  73. package/template/agent/skills/rust-developer/references/rust-rules/async-joinset-structured.md +0 -195
  74. package/template/agent/skills/rust-developer/references/rust-rules/async-mpsc-queue.md +0 -171
  75. package/template/agent/skills/rust-developer/references/rust-rules/async-no-lock-await.md +0 -156
  76. package/template/agent/skills/rust-developer/references/rust-rules/async-oneshot-response.md +0 -191
  77. package/template/agent/skills/rust-developer/references/rust-rules/async-select-racing.md +0 -198
  78. package/template/agent/skills/rust-developer/references/rust-rules/async-spawn-blocking.md +0 -154
  79. package/template/agent/skills/rust-developer/references/rust-rules/async-tokio-fs.md +0 -167
  80. package/template/agent/skills/rust-developer/references/rust-rules/async-tokio-runtime.md +0 -169
  81. package/template/agent/skills/rust-developer/references/rust-rules/async-try-join.md +0 -172
  82. package/template/agent/skills/rust-developer/references/rust-rules/async-watch-latest.md +0 -189
  83. package/template/agent/skills/rust-developer/references/rust-rules/doc-all-public.md +0 -113
  84. package/template/agent/skills/rust-developer/references/rust-rules/doc-cargo-metadata.md +0 -147
  85. package/template/agent/skills/rust-developer/references/rust-rules/doc-errors-section.md +0 -122
  86. package/template/agent/skills/rust-developer/references/rust-rules/doc-examples-section.md +0 -161
  87. package/template/agent/skills/rust-developer/references/rust-rules/doc-hidden-setup.md +0 -149
  88. package/template/agent/skills/rust-developer/references/rust-rules/doc-intra-links.md +0 -138
  89. package/template/agent/skills/rust-developer/references/rust-rules/doc-link-types.md +0 -169
  90. package/template/agent/skills/rust-developer/references/rust-rules/doc-module-inner.md +0 -116
  91. package/template/agent/skills/rust-developer/references/rust-rules/doc-panics-section.md +0 -128
  92. package/template/agent/skills/rust-developer/references/rust-rules/doc-question-mark.md +0 -136
  93. package/template/agent/skills/rust-developer/references/rust-rules/doc-safety-section.md +0 -131
  94. package/template/agent/skills/rust-developer/references/rust-rules/err-anyhow-app.md +0 -179
  95. package/template/agent/skills/rust-developer/references/rust-rules/err-context-chain.md +0 -144
  96. package/template/agent/skills/rust-developer/references/rust-rules/err-custom-type.md +0 -152
  97. package/template/agent/skills/rust-developer/references/rust-rules/err-doc-errors.md +0 -145
  98. package/template/agent/skills/rust-developer/references/rust-rules/err-expect-bugs-only.md +0 -133
  99. package/template/agent/skills/rust-developer/references/rust-rules/err-from-impl.md +0 -152
  100. package/template/agent/skills/rust-developer/references/rust-rules/err-lowercase-msg.md +0 -124
  101. package/template/agent/skills/rust-developer/references/rust-rules/err-no-unwrap-prod.md +0 -115
  102. package/template/agent/skills/rust-developer/references/rust-rules/err-question-mark.md +0 -151
  103. package/template/agent/skills/rust-developer/references/rust-rules/err-result-over-panic.md +0 -130
  104. package/template/agent/skills/rust-developer/references/rust-rules/err-source-chain.md +0 -155
  105. package/template/agent/skills/rust-developer/references/rust-rules/err-thiserror-lib.md +0 -171
  106. package/template/agent/skills/rust-developer/references/rust-rules/lint-cargo-metadata.md +0 -138
  107. package/template/agent/skills/rust-developer/references/rust-rules/lint-deny-correctness.md +0 -107
  108. package/template/agent/skills/rust-developer/references/rust-rules/lint-missing-docs.md +0 -154
  109. package/template/agent/skills/rust-developer/references/rust-rules/lint-pedantic-selective.md +0 -118
  110. package/template/agent/skills/rust-developer/references/rust-rules/lint-rustfmt-check.md +0 -157
  111. package/template/agent/skills/rust-developer/references/rust-rules/lint-unsafe-doc.md +0 -133
  112. package/template/agent/skills/rust-developer/references/rust-rules/lint-warn-complexity.md +0 -131
  113. package/template/agent/skills/rust-developer/references/rust-rules/lint-warn-perf.md +0 -136
  114. package/template/agent/skills/rust-developer/references/rust-rules/lint-warn-style.md +0 -135
  115. package/template/agent/skills/rust-developer/references/rust-rules/lint-warn-suspicious.md +0 -122
  116. package/template/agent/skills/rust-developer/references/rust-rules/lint-workspace-lints.md +0 -172
  117. package/template/agent/skills/rust-developer/references/rust-rules/mem-arena-allocator.md +0 -168
  118. package/template/agent/skills/rust-developer/references/rust-rules/mem-arrayvec.md +0 -142
  119. package/template/agent/skills/rust-developer/references/rust-rules/mem-assert-type-size.md +0 -168
  120. package/template/agent/skills/rust-developer/references/rust-rules/mem-avoid-format.md +0 -147
  121. package/template/agent/skills/rust-developer/references/rust-rules/mem-box-large-variant.md +0 -158
  122. package/template/agent/skills/rust-developer/references/rust-rules/mem-boxed-slice.md +0 -139
  123. package/template/agent/skills/rust-developer/references/rust-rules/mem-clone-from.md +0 -147
  124. package/template/agent/skills/rust-developer/references/rust-rules/mem-compact-string.md +0 -149
  125. package/template/agent/skills/rust-developer/references/rust-rules/mem-reuse-collections.md +0 -174
  126. package/template/agent/skills/rust-developer/references/rust-rules/mem-smaller-integers.md +0 -159
  127. package/template/agent/skills/rust-developer/references/rust-rules/mem-smallvec.md +0 -138
  128. package/template/agent/skills/rust-developer/references/rust-rules/mem-thinvec.md +0 -142
  129. package/template/agent/skills/rust-developer/references/rust-rules/mem-with-capacity.md +0 -156
  130. package/template/agent/skills/rust-developer/references/rust-rules/mem-write-over-format.md +0 -172
  131. package/template/agent/skills/rust-developer/references/rust-rules/mem-zero-copy.md +0 -164
  132. package/template/agent/skills/rust-developer/references/rust-rules/name-acronym-word.md +0 -99
  133. package/template/agent/skills/rust-developer/references/rust-rules/name-as-free.md +0 -104
  134. package/template/agent/skills/rust-developer/references/rust-rules/name-consts-screaming.md +0 -94
  135. package/template/agent/skills/rust-developer/references/rust-rules/name-crate-no-rs.md +0 -78
  136. package/template/agent/skills/rust-developer/references/rust-rules/name-funcs-snake.md +0 -76
  137. package/template/agent/skills/rust-developer/references/rust-rules/name-into-ownership.md +0 -123
  138. package/template/agent/skills/rust-developer/references/rust-rules/name-is-has-bool.md +0 -127
  139. package/template/agent/skills/rust-developer/references/rust-rules/name-iter-convention.md +0 -129
  140. package/template/agent/skills/rust-developer/references/rust-rules/name-iter-method.md +0 -131
  141. package/template/agent/skills/rust-developer/references/rust-rules/name-iter-type-match.md +0 -142
  142. package/template/agent/skills/rust-developer/references/rust-rules/name-lifetime-short.md +0 -86
  143. package/template/agent/skills/rust-developer/references/rust-rules/name-no-get-prefix.md +0 -154
  144. package/template/agent/skills/rust-developer/references/rust-rules/name-to-expensive.md +0 -118
  145. package/template/agent/skills/rust-developer/references/rust-rules/name-type-param-single.md +0 -92
  146. package/template/agent/skills/rust-developer/references/rust-rules/name-types-camel.md +0 -65
  147. package/template/agent/skills/rust-developer/references/rust-rules/name-variants-camel.md +0 -101
  148. package/template/agent/skills/rust-developer/references/rust-rules/opt-bounds-check.md +0 -161
  149. package/template/agent/skills/rust-developer/references/rust-rules/opt-cache-friendly.md +0 -187
  150. package/template/agent/skills/rust-developer/references/rust-rules/opt-codegen-units.md +0 -142
  151. package/template/agent/skills/rust-developer/references/rust-rules/opt-cold-unlikely.md +0 -152
  152. package/template/agent/skills/rust-developer/references/rust-rules/opt-inline-always-rare.md +0 -141
  153. package/template/agent/skills/rust-developer/references/rust-rules/opt-inline-never-cold.md +0 -181
  154. package/template/agent/skills/rust-developer/references/rust-rules/opt-inline-small.md +0 -160
  155. package/template/agent/skills/rust-developer/references/rust-rules/opt-likely-hint.md +0 -171
  156. package/template/agent/skills/rust-developer/references/rust-rules/opt-lto-release.md +0 -130
  157. package/template/agent/skills/rust-developer/references/rust-rules/opt-pgo-profile.md +0 -167
  158. package/template/agent/skills/rust-developer/references/rust-rules/opt-simd-portable.md +0 -144
  159. package/template/agent/skills/rust-developer/references/rust-rules/opt-target-cpu.md +0 -154
  160. package/template/agent/skills/rust-developer/references/rust-rules/own-arc-shared.md +0 -141
  161. package/template/agent/skills/rust-developer/references/rust-rules/own-borrow-over-clone.md +0 -95
  162. package/template/agent/skills/rust-developer/references/rust-rules/own-clone-explicit.md +0 -135
  163. package/template/agent/skills/rust-developer/references/rust-rules/own-copy-small.md +0 -124
  164. package/template/agent/skills/rust-developer/references/rust-rules/own-cow-conditional.md +0 -135
  165. package/template/agent/skills/rust-developer/references/rust-rules/own-lifetime-elision.md +0 -134
  166. package/template/agent/skills/rust-developer/references/rust-rules/own-move-large.md +0 -134
  167. package/template/agent/skills/rust-developer/references/rust-rules/own-mutex-interior.md +0 -105
  168. package/template/agent/skills/rust-developer/references/rust-rules/own-rc-single-thread.md +0 -65
  169. package/template/agent/skills/rust-developer/references/rust-rules/own-refcell-interior.md +0 -97
  170. package/template/agent/skills/rust-developer/references/rust-rules/own-rwlock-readers.md +0 -122
  171. package/template/agent/skills/rust-developer/references/rust-rules/own-slice-over-vec.md +0 -119
  172. package/template/agent/skills/rust-developer/references/rust-rules/perf-black-box-bench.md +0 -153
  173. package/template/agent/skills/rust-developer/references/rust-rules/perf-chain-avoid.md +0 -136
  174. package/template/agent/skills/rust-developer/references/rust-rules/perf-collect-into.md +0 -133
  175. package/template/agent/skills/rust-developer/references/rust-rules/perf-collect-once.md +0 -120
  176. package/template/agent/skills/rust-developer/references/rust-rules/perf-drain-reuse.md +0 -137
  177. package/template/agent/skills/rust-developer/references/rust-rules/perf-entry-api.md +0 -134
  178. package/template/agent/skills/rust-developer/references/rust-rules/perf-extend-batch.md +0 -150
  179. package/template/agent/skills/rust-developer/references/rust-rules/perf-iter-lazy.md +0 -123
  180. package/template/agent/skills/rust-developer/references/rust-rules/perf-iter-over-index.md +0 -113
  181. package/template/agent/skills/rust-developer/references/rust-rules/perf-profile-first.md +0 -175
  182. package/template/agent/skills/rust-developer/references/rust-rules/perf-release-profile.md +0 -149
  183. package/template/agent/skills/rust-developer/references/rust-rules/proj-bin-dir.md +0 -142
  184. package/template/agent/skills/rust-developer/references/rust-rules/proj-flat-small.md +0 -133
  185. package/template/agent/skills/rust-developer/references/rust-rules/proj-lib-main-split.md +0 -148
  186. package/template/agent/skills/rust-developer/references/rust-rules/proj-mod-by-feature.md +0 -130
  187. package/template/agent/skills/rust-developer/references/rust-rules/proj-mod-rs-dir.md +0 -120
  188. package/template/agent/skills/rust-developer/references/rust-rules/proj-prelude-module.md +0 -155
  189. package/template/agent/skills/rust-developer/references/rust-rules/proj-pub-crate-internal.md +0 -139
  190. package/template/agent/skills/rust-developer/references/rust-rules/proj-pub-super-parent.md +0 -135
  191. package/template/agent/skills/rust-developer/references/rust-rules/proj-pub-use-reexport.md +0 -162
  192. package/template/agent/skills/rust-developer/references/rust-rules/proj-workspace-deps.md +0 -186
  193. package/template/agent/skills/rust-developer/references/rust-rules/proj-workspace-large.md +0 -162
  194. package/template/agent/skills/rust-developer/references/rust-rules/test-arrange-act-assert.md +0 -160
  195. package/template/agent/skills/rust-developer/references/rust-rules/test-cfg-test-module.md +0 -151
  196. package/template/agent/skills/rust-developer/references/rust-rules/test-criterion-bench.md +0 -171
  197. package/template/agent/skills/rust-developer/references/rust-rules/test-descriptive-names.md +0 -142
  198. package/template/agent/skills/rust-developer/references/rust-rules/test-doctest-examples.md +0 -168
  199. package/template/agent/skills/rust-developer/references/rust-rules/test-fixture-raii.md +0 -151
  200. package/template/agent/skills/rust-developer/references/rust-rules/test-integration-dir.md +0 -144
  201. package/template/agent/skills/rust-developer/references/rust-rules/test-mock-traits.md +0 -189
  202. package/template/agent/skills/rust-developer/references/rust-rules/test-mockall-mocking.md +0 -226
  203. package/template/agent/skills/rust-developer/references/rust-rules/test-proptest-properties.md +0 -161
  204. package/template/agent/skills/rust-developer/references/rust-rules/test-should-panic.md +0 -130
  205. package/template/agent/skills/rust-developer/references/rust-rules/test-tokio-async.md +0 -154
  206. package/template/agent/skills/rust-developer/references/rust-rules/test-use-super.md +0 -127
  207. package/template/agent/skills/rust-developer/references/rust-rules/type-enum-states.md +0 -154
  208. package/template/agent/skills/rust-developer/references/rust-rules/type-generic-bounds.md +0 -142
  209. package/template/agent/skills/rust-developer/references/rust-rules/type-never-diverge.md +0 -146
  210. package/template/agent/skills/rust-developer/references/rust-rules/type-newtype-ids.md +0 -160
  211. package/template/agent/skills/rust-developer/references/rust-rules/type-newtype-validated.md +0 -159
  212. package/template/agent/skills/rust-developer/references/rust-rules/type-no-stringly.md +0 -144
  213. package/template/agent/skills/rust-developer/references/rust-rules/type-option-nullable.md +0 -137
  214. package/template/agent/skills/rust-developer/references/rust-rules/type-phantom-marker.md +0 -188
  215. package/template/agent/skills/rust-developer/references/rust-rules/type-repr-transparent.md +0 -143
  216. package/template/agent/skills/rust-developer/references/rust-rules/type-result-fallible.md +0 -131
  217. package/template/agent/skills/saas-architect/SKILL.md +0 -139
  218. package/template/agent/skills/security-engineer/SKILL.md +0 -133
  219. package/template/agent/skills/seo-specialist/SKILL.md +0 -130
  220. package/template/agent/skills/solo-founder-ops/SKILL.md +0 -56
@@ -1,151 +0,0 @@
1
- # err-question-mark
2
-
3
- > Use `?` operator for clean propagation
4
-
5
- ## Why It Matters
6
-
7
- The `?` operator is Rust's idiomatic way to propagate errors. It's concise, readable, and automatically converts between compatible error types using `From`. It replaces verbose `match` or `unwrap()` calls.
8
-
9
- ## Bad
10
-
11
- ```rust
12
- // Verbose match-based error handling
13
- fn load_config() -> Result<Config, Error> {
14
- let content = match std::fs::read_to_string("config.toml") {
15
- Ok(c) => c,
16
- Err(e) => return Err(Error::Io(e)),
17
- };
18
-
19
- let config = match toml::from_str(&content) {
20
- Ok(c) => c,
21
- Err(e) => return Err(Error::Parse(e)),
22
- };
23
-
24
- Ok(config)
25
- }
26
-
27
- // Or worse - using unwrap
28
- fn load_config_bad() -> Config {
29
- let content = std::fs::read_to_string("config.toml").unwrap();
30
- toml::from_str(&content).unwrap()
31
- }
32
- ```
33
-
34
- ## Good
35
-
36
- ```rust
37
- fn load_config() -> Result<Config, Error> {
38
- let content = std::fs::read_to_string("config.toml")?;
39
- let config = toml::from_str(&content)?;
40
- Ok(config)
41
- }
42
-
43
- // Even more concise
44
- fn load_config() -> Result<Config, Error> {
45
- Ok(toml::from_str(&std::fs::read_to_string("config.toml")?)?)
46
- }
47
- ```
48
-
49
- ## How ? Works
50
-
51
- ```rust
52
- // This:
53
- let x = expr?;
54
-
55
- // Expands roughly to:
56
- let x = match expr {
57
- Ok(val) => val,
58
- Err(err) => return Err(From::from(err)),
59
- };
60
- ```
61
-
62
- ## Combining with Context
63
-
64
- ```rust
65
- use anyhow::{Context, Result};
66
-
67
- fn load_user(id: u64) -> Result<User> {
68
- let path = format!("users/{}.json", id);
69
-
70
- let content = std::fs::read_to_string(&path)
71
- .with_context(|| format!("failed to read user file: {}", path))?;
72
-
73
- let user: User = serde_json::from_str(&content)
74
- .context("failed to parse user JSON")?;
75
-
76
- Ok(user)
77
- }
78
- ```
79
-
80
- ## ? with Option
81
-
82
- ```rust
83
- fn get_first_word(text: &str) -> Option<&str> {
84
- let first_line = text.lines().next()?;
85
- let first_word = first_line.split_whitespace().next()?;
86
- Some(first_word)
87
- }
88
-
89
- // Convert Option to Result
90
- fn get_required_config(key: &str) -> Result<String, Error> {
91
- config.get(key)
92
- .cloned()
93
- .ok_or_else(|| Error::MissingConfig(key.to_string()))
94
- }
95
- ```
96
-
97
- ## Error Type Conversion
98
-
99
- ```rust
100
- use thiserror::Error;
101
-
102
- #[derive(Error, Debug)]
103
- enum MyError {
104
- #[error("io error")]
105
- Io(#[from] std::io::Error), // Auto From impl
106
-
107
- #[error("parse error")]
108
- Parse(#[from] serde_json::Error), // Auto From impl
109
- }
110
-
111
- fn process() -> Result<(), MyError> {
112
- // ? automatically converts io::Error to MyError via From
113
- let content = std::fs::read_to_string("file.txt")?;
114
-
115
- // ? automatically converts serde_json::Error to MyError
116
- let data: Data = serde_json::from_str(&content)?;
117
-
118
- Ok(())
119
- }
120
- ```
121
-
122
- ## In main()
123
-
124
- ```rust
125
- // Option 1: Return Result from main
126
- fn main() -> Result<(), Box<dyn std::error::Error>> {
127
- let config = load_config()?;
128
- run_app(config)?;
129
- Ok(())
130
- }
131
-
132
- // Option 2: Handle in main, exit on error
133
- fn main() {
134
- if let Err(e) = run() {
135
- eprintln!("Error: {:#}", e);
136
- std::process::exit(1);
137
- }
138
- }
139
-
140
- fn run() -> anyhow::Result<()> {
141
- let config = load_config()?;
142
- run_app(config)?;
143
- Ok(())
144
- }
145
- ```
146
-
147
- ## See Also
148
-
149
- - [err-context-chain](err-context-chain.md) - Add context with .context()
150
- - [err-from-impl](err-from-impl.md) - Use #[from] for automatic conversion
151
- - [err-anyhow-app](err-anyhow-app.md) - Use anyhow for applications
@@ -1,130 +0,0 @@
1
- # err-result-over-panic
2
-
3
- > Return `Result<T, E>` instead of panicking for recoverable errors
4
-
5
- ## Why It Matters
6
-
7
- Panics unwind the stack and crash the thread (or program). They're unrecoverable from the caller's perspective. `Result<T, E>` gives callers the ability to decide how to handle errors—retry, fallback, propagate, or log. Libraries should almost never panic; applications should minimize panics to truly unrecoverable situations.
8
-
9
- ## Bad
10
-
11
- ```rust
12
- fn parse_config(path: &str) -> Config {
13
- let content = std::fs::read_to_string(path)
14
- .expect("Failed to read config"); // Crashes on missing file
15
-
16
- serde_json::from_str(&content)
17
- .expect("Invalid config format") // Crashes on bad JSON
18
- }
19
-
20
- fn divide(a: i32, b: i32) -> i32 {
21
- if b == 0 {
22
- panic!("Division by zero!"); // Crashes the program
23
- }
24
- a / b
25
- }
26
- ```
27
-
28
- Caller has no chance to recover or provide a fallback.
29
-
30
- ## Good
31
-
32
- ```rust
33
- use thiserror::Error;
34
-
35
- #[derive(Error, Debug)]
36
- enum ConfigError {
37
- #[error("Failed to read config file: {0}")]
38
- Io(#[from] std::io::Error),
39
- #[error("Invalid config format: {0}")]
40
- Parse(#[from] serde_json::Error),
41
- }
42
-
43
- fn parse_config(path: &str) -> Result<Config, ConfigError> {
44
- let content = std::fs::read_to_string(path)?;
45
- let config = serde_json::from_str(&content)?;
46
- Ok(config)
47
- }
48
-
49
- fn divide(a: i32, b: i32) -> Result<i32, &'static str> {
50
- if b == 0 {
51
- return Err("Division by zero");
52
- }
53
- Ok(a / b)
54
- }
55
-
56
- // Caller decides how to handle
57
- match parse_config("app.json") {
58
- Ok(config) => run_app(config),
59
- Err(e) => {
60
- eprintln!("Using default config: {}", e);
61
- run_app(Config::default())
62
- }
63
- }
64
- ```
65
-
66
- ## When Panic IS Appropriate
67
-
68
- ```rust
69
- // 1. Bug in the program (invariant violation)
70
- fn get_cached_value(&self, key: &str) -> &Value {
71
- self.cache.get(key).expect("BUG: key was verified to exist")
72
- }
73
-
74
- // 2. Setup/initialization that can't reasonably fail
75
- fn main() {
76
- let config = Config::load().expect("Failed to load required config");
77
- // Can't run without config, panic is reasonable
78
- }
79
-
80
- // 3. Tests
81
- #[test]
82
- fn test_parse() {
83
- let result = parse("valid input").unwrap(); // unwrap OK in tests
84
- assert_eq!(result, expected);
85
- }
86
-
87
- // 4. Examples and prototypes
88
- fn main() {
89
- // Quick prototype, panic is fine
90
- let data = fetch_data().unwrap();
91
- }
92
- ```
93
-
94
- ## Panic vs Result Decision Guide
95
-
96
- | Situation | Use |
97
- |-----------|-----|
98
- | File not found | `Result` |
99
- | Network error | `Result` |
100
- | Invalid user input | `Result` |
101
- | Parse error | `Result` |
102
- | Index out of bounds (from user data) | `Result` |
103
- | Index out of bounds (internal bug) | Panic |
104
- | Violated internal invariant | Panic |
105
- | Unimplemented code path | Panic (`unimplemented!()`) |
106
- | Impossible state reached | Panic (`unreachable!()`) |
107
-
108
- ## Library vs Application
109
-
110
- ```rust
111
- // Library: NEVER panic on user input
112
- pub fn parse(input: &str) -> Result<Ast, ParseError> {
113
- // Always return Result
114
- }
115
-
116
- // Application: Can panic at top level for critical failures
117
- fn main() {
118
- if let Err(e) = run() {
119
- eprintln!("Fatal error: {}", e);
120
- std::process::exit(1);
121
- }
122
- }
123
- ```
124
-
125
- ## See Also
126
-
127
- - [err-thiserror-lib](./err-thiserror-lib.md) - Define error types for libraries
128
- - [err-anyhow-app](./err-anyhow-app.md) - Ergonomic errors for applications
129
- - [err-no-unwrap-prod](./err-no-unwrap-prod.md) - Avoid unwrap in production code
130
- - [anti-unwrap-abuse](./anti-unwrap-abuse.md) - When unwrap is acceptable
@@ -1,155 +0,0 @@
1
- # err-source-chain
2
-
3
- > Preserve error chains with `#[source]` or `source()` method
4
-
5
- ## Why It Matters
6
-
7
- Errors often have underlying causes. Preserving the error chain (via `source()` method) allows logging frameworks and error reporters to show the full context: "config parse failed → JSON syntax error at line 5 → unexpected token". Without chaining, you lose valuable debugging information.
8
-
9
- ## Bad
10
-
11
- ```rust
12
- #[derive(Debug)]
13
- enum ConfigError {
14
- ParseFailed(String), // Lost the original serde_json::Error
15
- }
16
-
17
- fn load_config(path: &str) -> Result<Config, ConfigError> {
18
- let content = std::fs::read_to_string(path)
19
- .map_err(|e| ConfigError::ParseFailed(e.to_string()))?; // Chain lost!
20
-
21
- serde_json::from_str(&content)
22
- .map_err(|e| ConfigError::ParseFailed(e.to_string()))? // No source
23
- }
24
-
25
- // Error output: "Parse failed: invalid type: ..."
26
- // Missing: which file? what line? what was the parent error?
27
- ```
28
-
29
- ## Good
30
-
31
- ```rust
32
- use thiserror::Error;
33
-
34
- #[derive(Error, Debug)]
35
- enum ConfigError {
36
- #[error("Failed to read config file '{path}'")]
37
- ReadFailed {
38
- path: String,
39
- #[source] // Preserves the error chain
40
- source: std::io::Error,
41
- },
42
-
43
- #[error("Failed to parse config file '{path}'")]
44
- ParseFailed {
45
- path: String,
46
- #[source] // Original parse error preserved
47
- source: serde_json::Error,
48
- },
49
- }
50
-
51
- fn load_config(path: &str) -> Result<Config, ConfigError> {
52
- let content = std::fs::read_to_string(path)
53
- .map_err(|source| ConfigError::ReadFailed {
54
- path: path.to_string(),
55
- source, // Chain preserved
56
- })?;
57
-
58
- serde_json::from_str(&content)
59
- .map_err(|source| ConfigError::ParseFailed {
60
- path: path.to_string(),
61
- source,
62
- })
63
- }
64
- ```
65
-
66
- ## Manual source() Implementation
67
-
68
- ```rust
69
- use std::error::Error;
70
-
71
- #[derive(Debug)]
72
- struct MyError {
73
- message: String,
74
- source: Option<Box<dyn Error + Send + Sync>>,
75
- }
76
-
77
- impl std::fmt::Display for MyError {
78
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
79
- write!(f, "{}", self.message)
80
- }
81
- }
82
-
83
- impl Error for MyError {
84
- fn source(&self) -> Option<&(dyn Error + 'static)> {
85
- self.source.as_ref().map(|e| e.as_ref() as &(dyn Error + 'static))
86
- }
87
- }
88
- ```
89
-
90
- ## Walking the Error Chain
91
-
92
- ```rust
93
- fn print_error_chain(error: &dyn std::error::Error) {
94
- eprintln!("Error: {}", error);
95
-
96
- let mut source = error.source();
97
- while let Some(err) = source {
98
- eprintln!("Caused by: {}", err);
99
- source = err.source();
100
- }
101
- }
102
-
103
- // With anyhow, use {:?} for full chain
104
- let result: anyhow::Result<()> = do_something();
105
- if let Err(e) = result {
106
- eprintln!("{:?}", e); // Prints full chain with backtraces
107
- }
108
- ```
109
-
110
- ## anyhow Context
111
-
112
- ```rust
113
- use anyhow::{Context, Result};
114
-
115
- fn load_config(path: &str) -> Result<Config> {
116
- let content = std::fs::read_to_string(path)
117
- .with_context(|| format!("Failed to read '{}'", path))?;
118
-
119
- let config: Config = serde_json::from_str(&content)
120
- .with_context(|| format!("Failed to parse '{}'", path))?;
121
-
122
- Ok(config)
123
- }
124
-
125
- // Output:
126
- // Error: Failed to parse 'config.json'
127
- // Caused by: expected `:` at line 5 column 10
128
- ```
129
-
130
- ## #[from] vs #[source]
131
-
132
- ```rust
133
- use thiserror::Error;
134
-
135
- #[derive(Error, Debug)]
136
- enum MyError {
137
- // #[from] = implements From + sets source
138
- #[error("IO error")]
139
- Io(#[from] std::io::Error),
140
-
141
- // #[source] = only sets source (no From impl)
142
- #[error("Parse error in file '{path}'")]
143
- Parse {
144
- path: String,
145
- #[source]
146
- source: serde_json::Error,
147
- },
148
- }
149
- ```
150
-
151
- ## See Also
152
-
153
- - [err-thiserror-lib](./err-thiserror-lib.md) - thiserror for error definitions
154
- - [err-context-chain](./err-context-chain.md) - Adding context to errors
155
- - [err-from-impl](./err-from-impl.md) - From implementations for ?
@@ -1,171 +0,0 @@
1
- # err-thiserror-lib
2
-
3
- > Use `thiserror` for library error types
4
-
5
- ## Why It Matters
6
-
7
- Libraries should expose typed, matchable errors so users can handle specific error conditions. `thiserror` generates `Error` trait implementations with minimal boilerplate, creating ergonomic error types that are easy to match against.
8
-
9
- ## Bad
10
-
11
- ```rust
12
- // String errors - not matchable
13
- fn parse(input: &str) -> Result<Data, String> {
14
- Err("parse error".to_string())
15
- }
16
-
17
- // Box<dyn Error> - not matchable
18
- fn load(path: &Path) -> Result<Data, Box<dyn std::error::Error>> {
19
- Err(Box::new(std::io::Error::new(std::io::ErrorKind::NotFound, "file not found")))
20
- }
21
-
22
- // Manual implementation - verbose
23
- #[derive(Debug)]
24
- enum MyError {
25
- Io(std::io::Error),
26
- Parse(String),
27
- }
28
-
29
- impl std::fmt::Display for MyError {
30
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
31
- match self {
32
- MyError::Io(e) => write!(f, "io error: {}", e),
33
- MyError::Parse(s) => write!(f, "parse error: {}", s),
34
- }
35
- }
36
- }
37
-
38
- impl std::error::Error for MyError {
39
- fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
40
- match self {
41
- MyError::Io(e) => Some(e),
42
- MyError::Parse(_) => None,
43
- }
44
- }
45
- }
46
- ```
47
-
48
- ## Good
49
-
50
- ```rust
51
- use thiserror::Error;
52
-
53
- #[derive(Error, Debug)]
54
- pub enum ParseError {
55
- #[error("invalid syntax at line {line}: {message}")]
56
- Syntax { line: usize, message: String },
57
-
58
- #[error("unexpected end of file")]
59
- UnexpectedEof,
60
-
61
- #[error("invalid utf-8 encoding")]
62
- Utf8(#[from] std::str::Utf8Error),
63
-
64
- #[error("io error reading input")]
65
- Io(#[from] std::io::Error),
66
- }
67
-
68
- // Usage
69
- fn parse(input: &str) -> Result<Ast, ParseError> {
70
- if input.is_empty() {
71
- return Err(ParseError::UnexpectedEof);
72
- }
73
- // ...
74
- }
75
-
76
- // Users can match specific errors
77
- match parse(input) {
78
- Ok(ast) => process(ast),
79
- Err(ParseError::Syntax { line, message }) => {
80
- eprintln!("Syntax error on line {}: {}", line, message);
81
- }
82
- Err(ParseError::UnexpectedEof) => {
83
- eprintln!("File ended unexpectedly");
84
- }
85
- Err(e) => eprintln!("Error: {}", e),
86
- }
87
- ```
88
-
89
- ## Key Attributes
90
-
91
- ```rust
92
- use thiserror::Error;
93
-
94
- #[derive(Error, Debug)]
95
- pub enum MyError {
96
- // Simple message
97
- #[error("operation failed")]
98
- Failed,
99
-
100
- // Interpolated fields
101
- #[error("invalid value: {0}")]
102
- InvalidValue(String),
103
-
104
- // Named fields
105
- #[error("connection to {host}:{port} failed")]
106
- Connection { host: String, port: u16 },
107
-
108
- // Automatic From impl with #[from]
109
- #[error("database error")]
110
- Database(#[from] sqlx::Error),
111
-
112
- // Source without From (manual conversion needed)
113
- #[error("validation failed")]
114
- Validation {
115
- #[source]
116
- cause: ValidationError,
117
- field: String,
118
- },
119
-
120
- // Transparent - delegates Display and source to inner
121
- #[error(transparent)]
122
- Other(#[from] anyhow::Error),
123
- }
124
- ```
125
-
126
- ## Error Chaining
127
-
128
- ```rust
129
- use thiserror::Error;
130
-
131
- #[derive(Error, Debug)]
132
- pub enum ConfigError {
133
- #[error("failed to read config file")]
134
- Read(#[source] std::io::Error),
135
-
136
- #[error("failed to parse config")]
137
- Parse(#[source] toml::de::Error),
138
-
139
- #[error("invalid config value for '{key}'")]
140
- InvalidValue {
141
- key: String,
142
- #[source]
143
- cause: ValueError,
144
- },
145
- }
146
-
147
- // Error chain is preserved
148
- fn load_config(path: &Path) -> Result<Config, ConfigError> {
149
- let content = std::fs::read_to_string(path)
150
- .map_err(ConfigError::Read)?;
151
-
152
- let config: Config = toml::from_str(&content)
153
- .map_err(ConfigError::Parse)?;
154
-
155
- Ok(config)
156
- }
157
- ```
158
-
159
- ## Library vs Application
160
-
161
- | Context | Crate | Why |
162
- |---------|-------|-----|
163
- | Library | `thiserror` | Typed errors users can match |
164
- | Application | `anyhow` | Easy error handling with context |
165
- | Both | `thiserror` for public API, `anyhow` internally | Best of both |
166
-
167
- ## See Also
168
-
169
- - [err-anyhow-app](err-anyhow-app.md) - Use anyhow for applications
170
- - [err-from-impl](err-from-impl.md) - Use #[from] for automatic conversion
171
- - [err-source-chain](err-source-chain.md) - Use #[source] to chain errors