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,195 +0,0 @@
1
- # async-joinset-structured
2
-
3
- > Use `JoinSet` for managing dynamic collections of spawned tasks
4
-
5
- ## Why It Matters
6
-
7
- When spawning a variable number of tasks, collecting `JoinHandle`s in a `Vec` and using `join_all` works but lacks flexibility. `JoinSet` provides a better abstraction: add/remove tasks dynamically, get results as they complete, and abort all on drop. It's the idiomatic way to manage task collections.
8
-
9
- ## Bad
10
-
11
- ```rust
12
- // Manual handle management
13
- let mut handles: Vec<JoinHandle<Result<Data>>> = Vec::new();
14
-
15
- for url in urls {
16
- handles.push(tokio::spawn(fetch(url)));
17
- }
18
-
19
- // Wait for all, in order (not as they complete)
20
- let results = futures::future::join_all(handles).await;
21
-
22
- // No easy way to cancel all, handle errors progressively, or add more tasks
23
- ```
24
-
25
- ## Good
26
-
27
- ```rust
28
- use tokio::task::JoinSet;
29
-
30
- let mut set = JoinSet::new();
31
-
32
- for url in urls {
33
- set.spawn(fetch(url.clone()));
34
- }
35
-
36
- // Process results as they complete
37
- while let Some(result) = set.join_next().await {
38
- match result {
39
- Ok(Ok(data)) => process(data),
40
- Ok(Err(e)) => log::error!("Task failed: {}", e),
41
- Err(e) => log::error!("Task panicked: {}", e),
42
- }
43
- }
44
-
45
- // All tasks done, set is empty
46
- ```
47
-
48
- ## Dynamic Task Addition
49
-
50
- ```rust
51
- use tokio::task::JoinSet;
52
-
53
- async fn worker_pool(mut rx: mpsc::Receiver<Task>) {
54
- let mut set = JoinSet::new();
55
- let max_concurrent = 10;
56
-
57
- loop {
58
- tokio::select! {
59
- // Accept new tasks if under limit
60
- Some(task) = rx.recv(), if set.len() < max_concurrent => {
61
- set.spawn(process_task(task));
62
- }
63
-
64
- // Process completed tasks
65
- Some(result) = set.join_next() => {
66
- handle_result(result);
67
- }
68
-
69
- // Exit when no tasks and channel closed
70
- else => break,
71
- }
72
- }
73
- }
74
- ```
75
-
76
- ## Abort on Drop
77
-
78
- ```rust
79
- use tokio::task::JoinSet;
80
-
81
- {
82
- let mut set = JoinSet::new();
83
- set.spawn(long_running_task());
84
- set.spawn(another_task());
85
-
86
- // Early exit
87
- return;
88
- } // JoinSet dropped here - all tasks are aborted!
89
-
90
- // Explicit abort
91
- let mut set = JoinSet::new();
92
- set.spawn(task());
93
- set.abort_all(); // Cancel all tasks
94
- ```
95
-
96
- ## Error Handling Pattern
97
-
98
- ```rust
99
- use tokio::task::JoinSet;
100
-
101
- async fn fetch_all(urls: &[String]) -> Vec<Result<Data, Error>> {
102
- let mut set = JoinSet::new();
103
- let mut results = Vec::new();
104
-
105
- for url in urls {
106
- set.spawn(fetch(url.clone()));
107
- }
108
-
109
- while let Some(join_result) = set.join_next().await {
110
- let result = match join_result {
111
- Ok(task_result) => task_result,
112
- Err(join_error) => {
113
- if join_error.is_panic() {
114
- Err(Error::TaskPanicked)
115
- } else {
116
- Err(Error::TaskCancelled)
117
- }
118
- }
119
- };
120
- results.push(result);
121
- }
122
-
123
- results
124
- }
125
- ```
126
-
127
- ## With Cancellation
128
-
129
- ```rust
130
- use tokio::task::JoinSet;
131
- use tokio_util::sync::CancellationToken;
132
-
133
- async fn run_workers(shutdown: CancellationToken) {
134
- let mut set = JoinSet::new();
135
-
136
- for i in 0..4 {
137
- let token = shutdown.child_token();
138
- set.spawn(async move {
139
- loop {
140
- tokio::select! {
141
- _ = token.cancelled() => break,
142
- _ = do_work(i) => {}
143
- }
144
- }
145
- });
146
- }
147
-
148
- // Wait for shutdown
149
- shutdown.cancelled().await;
150
-
151
- // Abort remaining tasks
152
- set.abort_all();
153
-
154
- // Wait for all to finish (drain aborted tasks)
155
- while set.join_next().await.is_some() {}
156
- }
157
- ```
158
-
159
- ## Spawning with Context
160
-
161
- ```rust
162
- use tokio::task::JoinSet;
163
-
164
- let mut set: JoinSet<(usize, Result<Data, Error>)> = JoinSet::new();
165
-
166
- for (index, url) in urls.iter().enumerate() {
167
- let url = url.clone();
168
- set.spawn(async move {
169
- (index, fetch(&url).await)
170
- });
171
- }
172
-
173
- // Results include their index
174
- while let Some(result) = set.join_next().await {
175
- if let Ok((index, data)) = result {
176
- results[index] = Some(data);
177
- }
178
- }
179
- ```
180
-
181
- ## JoinSet vs join_all
182
-
183
- | Feature | JoinSet | join_all |
184
- |---------|---------|----------|
185
- | Add tasks dynamically | Yes | No |
186
- | Results as-completed | Yes | No (all at once) |
187
- | Abort all on drop | Yes | No |
188
- | Cancel individual | Yes | No |
189
- | Memory efficient | Yes | Pre-allocates |
190
-
191
- ## See Also
192
-
193
- - [async-join-parallel](./async-join-parallel.md) - Static concurrent futures
194
- - [async-cancellation-token](./async-cancellation-token.md) - Cancellation patterns
195
- - [async-try-join](./async-try-join.md) - Error handling in joins
@@ -1,171 +0,0 @@
1
- # async-mpsc-queue
2
-
3
- > Use `mpsc` channels for async message queues between tasks
4
-
5
- ## Why It Matters
6
-
7
- `tokio::sync::mpsc` (multi-producer, single-consumer) is the workhorse channel for async Rust. It provides async send/receive, backpressure via bounded capacity, and efficient cloning of senders. It's the default choice for task-to-task communication.
8
-
9
- ## Bad
10
-
11
- ```rust
12
- use std::sync::mpsc; // Wrong! Blocks the async runtime
13
-
14
- let (tx, rx) = std::sync::mpsc::channel();
15
-
16
- tokio::spawn(async move {
17
- tx.send("hello").unwrap(); // Might block
18
- });
19
-
20
- tokio::spawn(async move {
21
- let msg = rx.recv().unwrap(); // BLOCKS the executor thread!
22
- });
23
- ```
24
-
25
- ## Good
26
-
27
- ```rust
28
- use tokio::sync::mpsc;
29
-
30
- let (tx, mut rx) = mpsc::channel::<String>(100);
31
-
32
- tokio::spawn(async move {
33
- tx.send("hello".to_string()).await.unwrap();
34
- });
35
-
36
- tokio::spawn(async move {
37
- while let Some(msg) = rx.recv().await {
38
- println!("Received: {}", msg);
39
- }
40
- });
41
- ```
42
-
43
- ## Sender Cloning
44
-
45
- ```rust
46
- use tokio::sync::mpsc;
47
-
48
- let (tx, mut rx) = mpsc::channel::<Event>(100);
49
-
50
- // Multiple producers
51
- for i in 0..10 {
52
- let tx = tx.clone(); // Cheap clone
53
- tokio::spawn(async move {
54
- tx.send(Event { source: i }).await.unwrap();
55
- });
56
- }
57
-
58
- // Drop original sender so channel closes when all clones dropped
59
- drop(tx);
60
-
61
- // Consumer
62
- while let Some(event) = rx.recv().await {
63
- process(event);
64
- }
65
- // Loop exits when all senders dropped
66
- ```
67
-
68
- ## Message Handler Pattern
69
-
70
- ```rust
71
- use tokio::sync::mpsc;
72
-
73
- enum Command {
74
- Get { key: String, reply: oneshot::Sender<Option<Value>> },
75
- Set { key: String, value: Value },
76
- Delete { key: String },
77
- }
78
-
79
- async fn run_store(mut commands: mpsc::Receiver<Command>) {
80
- let mut store = HashMap::new();
81
-
82
- while let Some(cmd) = commands.recv().await {
83
- match cmd {
84
- Command::Get { key, reply } => {
85
- let _ = reply.send(store.get(&key).cloned());
86
- }
87
- Command::Set { key, value } => {
88
- store.insert(key, value);
89
- }
90
- Command::Delete { key } => {
91
- store.remove(&key);
92
- }
93
- }
94
- }
95
- }
96
-
97
- // Usage
98
- async fn client(tx: mpsc::Sender<Command>) -> Option<Value> {
99
- let (reply_tx, reply_rx) = oneshot::channel();
100
-
101
- tx.send(Command::Get {
102
- key: "foo".to_string(),
103
- reply: reply_tx
104
- }).await.unwrap();
105
-
106
- reply_rx.await.unwrap()
107
- }
108
- ```
109
-
110
- ## Graceful Shutdown
111
-
112
- ```rust
113
- async fn worker(mut rx: mpsc::Receiver<Task>, shutdown: CancellationToken) {
114
- loop {
115
- tokio::select! {
116
- _ = shutdown.cancelled() => {
117
- // Drain remaining messages
118
- while let Ok(task) = rx.try_recv() {
119
- process(task).await;
120
- }
121
- break;
122
- }
123
- Some(task) = rx.recv() => {
124
- process(task).await;
125
- }
126
- else => break, // Channel closed
127
- }
128
- }
129
- }
130
- ```
131
-
132
- ## WeakSender for Optional Producers
133
-
134
- ```rust
135
- use tokio::sync::mpsc;
136
-
137
- let (tx, mut rx) = mpsc::channel::<Message>(100);
138
- let weak = tx.downgrade(); // Doesn't keep channel alive
139
-
140
- tokio::spawn(async move {
141
- // Strong sender - keeps channel alive
142
- tx.send("from strong".into()).await.unwrap();
143
- });
144
-
145
- tokio::spawn(async move {
146
- // Weak sender - may fail if strong senders dropped
147
- if let Some(tx) = weak.upgrade() {
148
- tx.send("from weak".into()).await.unwrap();
149
- }
150
- });
151
- ```
152
-
153
- ## Permit Pattern
154
-
155
- ```rust
156
- // Reserve slot before preparing message
157
- let permit = tx.reserve().await?;
158
-
159
- // Now we have guaranteed capacity
160
- let message = expensive_to_create_message();
161
- permit.send(message); // Never fails
162
-
163
- // Useful when message creation is expensive
164
- // and you don't want to create it if channel is full
165
- ```
166
-
167
- ## See Also
168
-
169
- - [async-bounded-channel](./async-bounded-channel.md) - Why bounded channels
170
- - [async-oneshot-response](./async-oneshot-response.md) - Request-response with oneshot
171
- - [async-broadcast-pubsub](./async-broadcast-pubsub.md) - Multiple consumers
@@ -1,156 +0,0 @@
1
- # async-no-lock-await
2
-
3
- > Never hold `Mutex`/`RwLock` across `.await`
4
-
5
- ## Why It Matters
6
-
7
- Holding a lock across an `.await` point can cause deadlocks and severely hurt performance. The task may be suspended while holding the lock, blocking all other tasks waiting for it - potentially indefinitely.
8
-
9
- ## Bad
10
-
11
- ```rust
12
- use tokio::sync::Mutex;
13
-
14
- async fn bad_update(state: &Mutex<State>) {
15
- let mut guard = state.lock().await;
16
-
17
- // BAD: Lock held across await!
18
- let data = fetch_from_network().await;
19
-
20
- guard.value = data;
21
- } // Lock finally released
22
-
23
- // This can deadlock or starve other tasks
24
- ```
25
-
26
- ## Good
27
-
28
- ```rust
29
- use tokio::sync::Mutex;
30
-
31
- async fn good_update(state: &Mutex<State>) {
32
- // Fetch data BEFORE taking the lock
33
- let data = fetch_from_network().await;
34
-
35
- // Lock only for the quick update
36
- let mut guard = state.lock().await;
37
- guard.value = data;
38
- } // Lock released immediately
39
-
40
- // Alternative: Clone data out, process, then update
41
- async fn good_update_v2(state: &Mutex<State>) {
42
- // Extract what we need
43
- let id = {
44
- let guard = state.lock().await;
45
- guard.id.clone()
46
- }; // Lock released!
47
-
48
- // Do async work without lock
49
- let data = fetch_by_id(id).await;
50
-
51
- // Quick update
52
- state.lock().await.value = data;
53
- }
54
- ```
55
-
56
- ## The Problem Visualized
57
-
58
- ```rust
59
- // Task A:
60
- let guard = mutex.lock().await; // Acquires lock
61
- expensive_io().await; // Suspended, still holding lock!
62
- // ... many milliseconds pass ...
63
- drop(guard); // Finally releases
64
-
65
- // Task B, C, D:
66
- let guard = mutex.lock().await; // All blocked waiting for A!
67
- ```
68
-
69
- ## Patterns for Extraction
70
-
71
- ```rust
72
- use tokio::sync::Mutex;
73
-
74
- // Pattern 1: Clone out, process, update
75
- async fn pattern_clone(state: &Mutex<State>) {
76
- let config = state.lock().await.config.clone();
77
- let result = process_with_io(&config).await;
78
- state.lock().await.result = result;
79
- }
80
-
81
- // Pattern 2: Compute closure, apply
82
- async fn pattern_closure(state: &Mutex<State>) {
83
- let update = compute_update().await;
84
-
85
- state.lock().await.apply(update);
86
- }
87
-
88
- // Pattern 3: Message passing
89
- async fn pattern_message(
90
- state: &Mutex<State>,
91
- tx: mpsc::Sender<Update>,
92
- ) {
93
- let update = compute_update().await;
94
- tx.send(update).await.unwrap();
95
- }
96
-
97
- // Separate task handles updates
98
- async fn state_manager(
99
- state: Arc<Mutex<State>>,
100
- mut rx: mpsc::Receiver<Update>,
101
- ) {
102
- while let Some(update) = rx.recv().await {
103
- state.lock().await.apply(update);
104
- }
105
- }
106
- ```
107
-
108
- ## Using RwLock
109
-
110
- ```rust
111
- use tokio::sync::RwLock;
112
-
113
- async fn read_heavy(state: &RwLock<State>) {
114
- // Multiple readers OK, but still don't hold across await
115
- let value = {
116
- let guard = state.read().await;
117
- guard.value.clone()
118
- };
119
-
120
- // Process without lock
121
- let result = process(value).await;
122
-
123
- // Write lock for update
124
- state.write().await.result = result;
125
- }
126
- ```
127
-
128
- ## std::sync::Mutex vs tokio::sync::Mutex
129
-
130
- ```rust
131
- // std::sync::Mutex: Blocks the entire thread
132
- // - Use for quick, CPU-only operations
133
- // - NEVER use in async code with await inside
134
-
135
- // tokio::sync::Mutex: Async-aware, yields to runtime
136
- // - Use in async code
137
- // - Still don't hold across await points!
138
-
139
- // std::sync::Mutex in async (quick operation, OK):
140
- async fn quick_update(state: &std::sync::Mutex<State>) {
141
- state.lock().unwrap().counter += 1; // No await, OK
142
- }
143
-
144
- // tokio::sync::Mutex (must use if lock scope has await):
145
- async fn must_await_inside(state: &tokio::sync::Mutex<State>) {
146
- let mut guard = state.lock().await;
147
- // Only if you REALLY need the lock during async op
148
- // (usually you don't - redesign instead)
149
- }
150
- ```
151
-
152
- ## See Also
153
-
154
- - [async-spawn-blocking](async-spawn-blocking.md) - Use spawn_blocking for CPU work
155
- - [async-clone-before-await](async-clone-before-await.md) - Clone data before await
156
- - [anti-lock-across-await](anti-lock-across-await.md) - Anti-pattern reference
@@ -1,191 +0,0 @@
1
- # async-oneshot-response
2
-
3
- > Use `oneshot` channel for request-response patterns
4
-
5
- ## Why It Matters
6
-
7
- When one task needs to send a request and wait for exactly one response, `oneshot` is the perfect fit. It's a single-use channel optimized for this pattern—no buffering, no clone overhead. Combined with `mpsc`, it enables clean actor-style message passing.
8
-
9
- ## Bad
10
-
11
- ```rust
12
- // Using mpsc for single response - wasteful
13
- let (tx, mut rx) = mpsc::channel::<Response>(1);
14
- send_request().await;
15
- let response = rx.recv().await.unwrap();
16
- // Channel persists, could accidentally receive more
17
-
18
- // Using shared state - complex
19
- let result = Arc::new(Mutex::new(None));
20
- send_request(result.clone()).await;
21
- while result.lock().await.is_none() {
22
- tokio::time::sleep(Duration::from_millis(10)).await; // Polling!
23
- }
24
- ```
25
-
26
- ## Good
27
-
28
- ```rust
29
- use tokio::sync::oneshot;
30
-
31
- let (tx, rx) = oneshot::channel::<Response>();
32
-
33
- // Send request with reply channel
34
- send_request(Request { data, reply: tx }).await;
35
-
36
- // Wait for response
37
- let response = rx.await?;
38
-
39
- // Channel is consumed - can't accidentally reuse
40
- ```
41
-
42
- ## Request-Response Pattern
43
-
44
- ```rust
45
- use tokio::sync::{mpsc, oneshot};
46
-
47
- enum Request {
48
- Get {
49
- key: String,
50
- reply: oneshot::Sender<Option<Value>>,
51
- },
52
- Set {
53
- key: String,
54
- value: Value,
55
- reply: oneshot::Sender<bool>,
56
- },
57
- }
58
-
59
- // Service handler
60
- async fn service(mut rx: mpsc::Receiver<Request>) {
61
- let mut store = HashMap::new();
62
-
63
- while let Some(req) = rx.recv().await {
64
- match req {
65
- Request::Get { key, reply } => {
66
- let value = store.get(&key).cloned();
67
- let _ = reply.send(value); // Ignore if receiver dropped
68
- }
69
- Request::Set { key, value, reply } => {
70
- store.insert(key, value);
71
- let _ = reply.send(true);
72
- }
73
- }
74
- }
75
- }
76
-
77
- // Client
78
- async fn get_value(tx: &mpsc::Sender<Request>, key: &str) -> Option<Value> {
79
- let (reply_tx, reply_rx) = oneshot::channel();
80
-
81
- tx.send(Request::Get {
82
- key: key.to_string(),
83
- reply: reply_tx,
84
- }).await.ok()?;
85
-
86
- reply_rx.await.ok()?
87
- }
88
- ```
89
-
90
- ## With Timeout
91
-
92
- ```rust
93
- use tokio::time::{timeout, Duration};
94
-
95
- async fn request_with_timeout(
96
- tx: &mpsc::Sender<Request>,
97
- key: &str,
98
- ) -> Result<Value, Error> {
99
- let (reply_tx, reply_rx) = oneshot::channel();
100
-
101
- tx.send(Request::Get {
102
- key: key.to_string(),
103
- reply: reply_tx,
104
- }).await.map_err(|_| Error::ServiceDown)?;
105
-
106
- timeout(Duration::from_secs(5), reply_rx)
107
- .await
108
- .map_err(|_| Error::Timeout)?
109
- .map_err(|_| Error::ServiceDown)?
110
- .ok_or(Error::NotFound)
111
- }
112
- ```
113
-
114
- ## Error Handling
115
-
116
- ```rust
117
- use tokio::sync::oneshot;
118
-
119
- let (tx, rx) = oneshot::channel::<String>();
120
-
121
- // Sender dropped without sending
122
- drop(tx);
123
- match rx.await {
124
- Ok(value) => println!("Got: {}", value),
125
- Err(oneshot::error::RecvError { .. }) => {
126
- println!("Sender dropped");
127
- }
128
- }
129
-
130
- // Receiver dropped before send
131
- let (tx, rx) = oneshot::channel::<String>();
132
- drop(rx);
133
- match tx.send("hello".to_string()) {
134
- Ok(()) => println!("Sent"),
135
- Err(value) => println!("Receiver dropped, value: {}", value),
136
- }
137
- ```
138
-
139
- ## Closed Detection
140
-
141
- ```rust
142
- // Check if receiver is still waiting
143
- let (tx, rx) = oneshot::channel::<i32>();
144
-
145
- // In producer
146
- if tx.is_closed() {
147
- println!("Receiver already gone, skip expensive computation");
148
- } else {
149
- let result = expensive_computation();
150
- tx.send(result).ok();
151
- }
152
-
153
- // Async wait for close
154
- let tx_clone = tx.clone(); // Note: can't actually clone, just showing concept
155
- tokio::select! {
156
- _ = tx.closed() => println!("Receiver dropped"),
157
- result = compute() => { tx.send(result).ok(); }
158
- }
159
- ```
160
-
161
- ## Response Type Wrapper
162
-
163
- ```rust
164
- // Standardize request-response pattern
165
- struct RpcRequest<Req, Res> {
166
- request: Req,
167
- reply: oneshot::Sender<Res>,
168
- }
169
-
170
- impl<Req, Res> RpcRequest<Req, Res> {
171
- fn new(request: Req) -> (Self, oneshot::Receiver<Res>) {
172
- let (tx, rx) = oneshot::channel();
173
- (RpcRequest { request, reply: tx }, rx)
174
- }
175
-
176
- fn respond(self, response: Res) {
177
- let _ = self.reply.send(response);
178
- }
179
- }
180
-
181
- // Usage
182
- let (req, rx) = RpcRequest::new(GetUser { id: 42 });
183
- tx.send(req).await?;
184
- let user = rx.await?;
185
- ```
186
-
187
- ## See Also
188
-
189
- - [async-mpsc-queue](./async-mpsc-queue.md) - Pair with oneshot for request-response
190
- - [async-bounded-channel](./async-bounded-channel.md) - Channel sizing
191
- - [async-select-racing](./async-select-racing.md) - Timeout patterns