agy-superpowers 5.2.1 → 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 (233) hide show
  1. package/README.md +47 -150
  2. package/package.json +1 -1
  3. package/template/agent/patches/skills-patches.md +23 -0
  4. package/template/agent/rules/scratch-scripts.md +37 -0
  5. package/template/agent/rules/superpowers.md +6 -50
  6. package/template/agent/skills/brainstorming/SKILL.md +4 -3
  7. package/template/agent/skills/brainstorming/visual-companion.md +2 -3
  8. package/template/agent/skills/finishing-a-development-branch/SKILL.md +11 -16
  9. package/template/agent/skills/subagent-driven-development/SKILL.md +16 -0
  10. package/template/agent/skills/subagent-driven-development/implementer-prompt.md +4 -3
  11. package/template/agent/skills/using-git-worktrees/SKILL.md +3 -2
  12. package/template/agent/skills/using-superpowers/SKILL.md +8 -6
  13. package/template/agent/skills/using-superpowers/references/copilot-tools.md +52 -0
  14. package/template/agent/skills/writing-plans/SKILL.md +5 -3
  15. package/template/agent/skills/writing-skills/SKILL.md +1 -1
  16. package/template/agent/superpowers-version.json +2 -2
  17. package/template/agent/tmp/agent-config-backup.yml +9 -0
  18. package/template/agent/skills/ai-integrated-product/SKILL.md +0 -57
  19. package/template/agent/skills/analytics-setup/SKILL.md +0 -51
  20. package/template/agent/skills/api-design/SKILL.md +0 -193
  21. package/template/agent/skills/app-store-optimizer/SKILL.md +0 -127
  22. package/template/agent/skills/auth-and-identity/SKILL.md +0 -167
  23. package/template/agent/skills/backend-developer/SKILL.md +0 -148
  24. package/template/agent/skills/bootstrapper-finance/SKILL.md +0 -55
  25. package/template/agent/skills/chrome-extension-developer/SKILL.md +0 -53
  26. package/template/agent/skills/community-manager/SKILL.md +0 -115
  27. package/template/agent/skills/content-marketer/SKILL.md +0 -111
  28. package/template/agent/skills/conversion-optimizer/SKILL.md +0 -142
  29. package/template/agent/skills/cto-architect/SKILL.md +0 -133
  30. package/template/agent/skills/customer-success-manager/SKILL.md +0 -126
  31. package/template/agent/skills/data-analyst/SKILL.md +0 -147
  32. package/template/agent/skills/devops-engineer/SKILL.md +0 -117
  33. package/template/agent/skills/email-infrastructure/SKILL.md +0 -164
  34. package/template/agent/skills/game-design/SKILL.md +0 -194
  35. package/template/agent/skills/game-developer/SKILL.md +0 -175
  36. package/template/agent/skills/growth-hacker/SKILL.md +0 -122
  37. package/template/agent/skills/idea-validator/SKILL.md +0 -55
  38. package/template/agent/skills/indie-legal/SKILL.md +0 -53
  39. package/template/agent/skills/influencer-marketer/SKILL.md +0 -141
  40. package/template/agent/skills/landing-page-builder/SKILL.md +0 -59
  41. package/template/agent/skills/launch-strategist/SKILL.md +0 -62
  42. package/template/agent/skills/market-researcher/SKILL.md +0 -53
  43. package/template/agent/skills/micro-saas-builder/SKILL.md +0 -56
  44. package/template/agent/skills/monetization-strategist/SKILL.md +0 -119
  45. package/template/agent/skills/paid-acquisition-specialist/SKILL.md +0 -119
  46. package/template/agent/skills/pricing-psychologist/SKILL.md +0 -58
  47. package/template/agent/skills/real-time-features/SKILL.md +0 -194
  48. package/template/agent/skills/retention-specialist/SKILL.md +0 -123
  49. package/template/agent/skills/rust-developer/SKILL.md +0 -281
  50. package/template/agent/skills/rust-developer/references/rust-rules/_sections.md +0 -231
  51. package/template/agent/skills/rust-developer/references/rust-rules/anti-clone-excessive.md +0 -124
  52. package/template/agent/skills/rust-developer/references/rust-rules/anti-collect-intermediate.md +0 -131
  53. package/template/agent/skills/rust-developer/references/rust-rules/anti-empty-catch.md +0 -132
  54. package/template/agent/skills/rust-developer/references/rust-rules/anti-expect-lazy.md +0 -95
  55. package/template/agent/skills/rust-developer/references/rust-rules/anti-format-hot-path.md +0 -141
  56. package/template/agent/skills/rust-developer/references/rust-rules/anti-index-over-iter.md +0 -125
  57. package/template/agent/skills/rust-developer/references/rust-rules/anti-lock-across-await.md +0 -127
  58. package/template/agent/skills/rust-developer/references/rust-rules/anti-over-abstraction.md +0 -120
  59. package/template/agent/skills/rust-developer/references/rust-rules/anti-panic-expected.md +0 -131
  60. package/template/agent/skills/rust-developer/references/rust-rules/anti-premature-optimize.md +0 -156
  61. package/template/agent/skills/rust-developer/references/rust-rules/anti-string-for-str.md +0 -122
  62. package/template/agent/skills/rust-developer/references/rust-rules/anti-stringly-typed.md +0 -167
  63. package/template/agent/skills/rust-developer/references/rust-rules/anti-type-erasure.md +0 -134
  64. package/template/agent/skills/rust-developer/references/rust-rules/anti-unwrap-abuse.md +0 -143
  65. package/template/agent/skills/rust-developer/references/rust-rules/anti-vec-for-slice.md +0 -121
  66. package/template/agent/skills/rust-developer/references/rust-rules/api-builder-must-use.md +0 -143
  67. package/template/agent/skills/rust-developer/references/rust-rules/api-builder-pattern.md +0 -187
  68. package/template/agent/skills/rust-developer/references/rust-rules/api-common-traits.md +0 -165
  69. package/template/agent/skills/rust-developer/references/rust-rules/api-default-impl.md +0 -177
  70. package/template/agent/skills/rust-developer/references/rust-rules/api-extension-trait.md +0 -163
  71. package/template/agent/skills/rust-developer/references/rust-rules/api-from-not-into.md +0 -146
  72. package/template/agent/skills/rust-developer/references/rust-rules/api-impl-asref.md +0 -142
  73. package/template/agent/skills/rust-developer/references/rust-rules/api-impl-into.md +0 -160
  74. package/template/agent/skills/rust-developer/references/rust-rules/api-must-use.md +0 -125
  75. package/template/agent/skills/rust-developer/references/rust-rules/api-newtype-safety.md +0 -162
  76. package/template/agent/skills/rust-developer/references/rust-rules/api-non-exhaustive.md +0 -177
  77. package/template/agent/skills/rust-developer/references/rust-rules/api-parse-dont-validate.md +0 -184
  78. package/template/agent/skills/rust-developer/references/rust-rules/api-sealed-trait.md +0 -168
  79. package/template/agent/skills/rust-developer/references/rust-rules/api-serde-optional.md +0 -182
  80. package/template/agent/skills/rust-developer/references/rust-rules/api-typestate.md +0 -199
  81. package/template/agent/skills/rust-developer/references/rust-rules/async-bounded-channel.md +0 -175
  82. package/template/agent/skills/rust-developer/references/rust-rules/async-broadcast-pubsub.md +0 -185
  83. package/template/agent/skills/rust-developer/references/rust-rules/async-cancellation-token.md +0 -203
  84. package/template/agent/skills/rust-developer/references/rust-rules/async-clone-before-await.md +0 -171
  85. package/template/agent/skills/rust-developer/references/rust-rules/async-join-parallel.md +0 -158
  86. package/template/agent/skills/rust-developer/references/rust-rules/async-joinset-structured.md +0 -195
  87. package/template/agent/skills/rust-developer/references/rust-rules/async-mpsc-queue.md +0 -171
  88. package/template/agent/skills/rust-developer/references/rust-rules/async-no-lock-await.md +0 -156
  89. package/template/agent/skills/rust-developer/references/rust-rules/async-oneshot-response.md +0 -191
  90. package/template/agent/skills/rust-developer/references/rust-rules/async-select-racing.md +0 -198
  91. package/template/agent/skills/rust-developer/references/rust-rules/async-spawn-blocking.md +0 -154
  92. package/template/agent/skills/rust-developer/references/rust-rules/async-tokio-fs.md +0 -167
  93. package/template/agent/skills/rust-developer/references/rust-rules/async-tokio-runtime.md +0 -169
  94. package/template/agent/skills/rust-developer/references/rust-rules/async-try-join.md +0 -172
  95. package/template/agent/skills/rust-developer/references/rust-rules/async-watch-latest.md +0 -189
  96. package/template/agent/skills/rust-developer/references/rust-rules/doc-all-public.md +0 -113
  97. package/template/agent/skills/rust-developer/references/rust-rules/doc-cargo-metadata.md +0 -147
  98. package/template/agent/skills/rust-developer/references/rust-rules/doc-errors-section.md +0 -122
  99. package/template/agent/skills/rust-developer/references/rust-rules/doc-examples-section.md +0 -161
  100. package/template/agent/skills/rust-developer/references/rust-rules/doc-hidden-setup.md +0 -149
  101. package/template/agent/skills/rust-developer/references/rust-rules/doc-intra-links.md +0 -138
  102. package/template/agent/skills/rust-developer/references/rust-rules/doc-link-types.md +0 -169
  103. package/template/agent/skills/rust-developer/references/rust-rules/doc-module-inner.md +0 -116
  104. package/template/agent/skills/rust-developer/references/rust-rules/doc-panics-section.md +0 -128
  105. package/template/agent/skills/rust-developer/references/rust-rules/doc-question-mark.md +0 -136
  106. package/template/agent/skills/rust-developer/references/rust-rules/doc-safety-section.md +0 -131
  107. package/template/agent/skills/rust-developer/references/rust-rules/err-anyhow-app.md +0 -179
  108. package/template/agent/skills/rust-developer/references/rust-rules/err-context-chain.md +0 -144
  109. package/template/agent/skills/rust-developer/references/rust-rules/err-custom-type.md +0 -152
  110. package/template/agent/skills/rust-developer/references/rust-rules/err-doc-errors.md +0 -145
  111. package/template/agent/skills/rust-developer/references/rust-rules/err-expect-bugs-only.md +0 -133
  112. package/template/agent/skills/rust-developer/references/rust-rules/err-from-impl.md +0 -152
  113. package/template/agent/skills/rust-developer/references/rust-rules/err-lowercase-msg.md +0 -124
  114. package/template/agent/skills/rust-developer/references/rust-rules/err-no-unwrap-prod.md +0 -115
  115. package/template/agent/skills/rust-developer/references/rust-rules/err-question-mark.md +0 -151
  116. package/template/agent/skills/rust-developer/references/rust-rules/err-result-over-panic.md +0 -130
  117. package/template/agent/skills/rust-developer/references/rust-rules/err-source-chain.md +0 -155
  118. package/template/agent/skills/rust-developer/references/rust-rules/err-thiserror-lib.md +0 -171
  119. package/template/agent/skills/rust-developer/references/rust-rules/lint-cargo-metadata.md +0 -138
  120. package/template/agent/skills/rust-developer/references/rust-rules/lint-deny-correctness.md +0 -107
  121. package/template/agent/skills/rust-developer/references/rust-rules/lint-missing-docs.md +0 -154
  122. package/template/agent/skills/rust-developer/references/rust-rules/lint-pedantic-selective.md +0 -118
  123. package/template/agent/skills/rust-developer/references/rust-rules/lint-rustfmt-check.md +0 -157
  124. package/template/agent/skills/rust-developer/references/rust-rules/lint-unsafe-doc.md +0 -133
  125. package/template/agent/skills/rust-developer/references/rust-rules/lint-warn-complexity.md +0 -131
  126. package/template/agent/skills/rust-developer/references/rust-rules/lint-warn-perf.md +0 -136
  127. package/template/agent/skills/rust-developer/references/rust-rules/lint-warn-style.md +0 -135
  128. package/template/agent/skills/rust-developer/references/rust-rules/lint-warn-suspicious.md +0 -122
  129. package/template/agent/skills/rust-developer/references/rust-rules/lint-workspace-lints.md +0 -172
  130. package/template/agent/skills/rust-developer/references/rust-rules/mem-arena-allocator.md +0 -168
  131. package/template/agent/skills/rust-developer/references/rust-rules/mem-arrayvec.md +0 -142
  132. package/template/agent/skills/rust-developer/references/rust-rules/mem-assert-type-size.md +0 -168
  133. package/template/agent/skills/rust-developer/references/rust-rules/mem-avoid-format.md +0 -147
  134. package/template/agent/skills/rust-developer/references/rust-rules/mem-box-large-variant.md +0 -158
  135. package/template/agent/skills/rust-developer/references/rust-rules/mem-boxed-slice.md +0 -139
  136. package/template/agent/skills/rust-developer/references/rust-rules/mem-clone-from.md +0 -147
  137. package/template/agent/skills/rust-developer/references/rust-rules/mem-compact-string.md +0 -149
  138. package/template/agent/skills/rust-developer/references/rust-rules/mem-reuse-collections.md +0 -174
  139. package/template/agent/skills/rust-developer/references/rust-rules/mem-smaller-integers.md +0 -159
  140. package/template/agent/skills/rust-developer/references/rust-rules/mem-smallvec.md +0 -138
  141. package/template/agent/skills/rust-developer/references/rust-rules/mem-thinvec.md +0 -142
  142. package/template/agent/skills/rust-developer/references/rust-rules/mem-with-capacity.md +0 -156
  143. package/template/agent/skills/rust-developer/references/rust-rules/mem-write-over-format.md +0 -172
  144. package/template/agent/skills/rust-developer/references/rust-rules/mem-zero-copy.md +0 -164
  145. package/template/agent/skills/rust-developer/references/rust-rules/name-acronym-word.md +0 -99
  146. package/template/agent/skills/rust-developer/references/rust-rules/name-as-free.md +0 -104
  147. package/template/agent/skills/rust-developer/references/rust-rules/name-consts-screaming.md +0 -94
  148. package/template/agent/skills/rust-developer/references/rust-rules/name-crate-no-rs.md +0 -78
  149. package/template/agent/skills/rust-developer/references/rust-rules/name-funcs-snake.md +0 -76
  150. package/template/agent/skills/rust-developer/references/rust-rules/name-into-ownership.md +0 -123
  151. package/template/agent/skills/rust-developer/references/rust-rules/name-is-has-bool.md +0 -127
  152. package/template/agent/skills/rust-developer/references/rust-rules/name-iter-convention.md +0 -129
  153. package/template/agent/skills/rust-developer/references/rust-rules/name-iter-method.md +0 -131
  154. package/template/agent/skills/rust-developer/references/rust-rules/name-iter-type-match.md +0 -142
  155. package/template/agent/skills/rust-developer/references/rust-rules/name-lifetime-short.md +0 -86
  156. package/template/agent/skills/rust-developer/references/rust-rules/name-no-get-prefix.md +0 -154
  157. package/template/agent/skills/rust-developer/references/rust-rules/name-to-expensive.md +0 -118
  158. package/template/agent/skills/rust-developer/references/rust-rules/name-type-param-single.md +0 -92
  159. package/template/agent/skills/rust-developer/references/rust-rules/name-types-camel.md +0 -65
  160. package/template/agent/skills/rust-developer/references/rust-rules/name-variants-camel.md +0 -101
  161. package/template/agent/skills/rust-developer/references/rust-rules/opt-bounds-check.md +0 -161
  162. package/template/agent/skills/rust-developer/references/rust-rules/opt-cache-friendly.md +0 -187
  163. package/template/agent/skills/rust-developer/references/rust-rules/opt-codegen-units.md +0 -142
  164. package/template/agent/skills/rust-developer/references/rust-rules/opt-cold-unlikely.md +0 -152
  165. package/template/agent/skills/rust-developer/references/rust-rules/opt-inline-always-rare.md +0 -141
  166. package/template/agent/skills/rust-developer/references/rust-rules/opt-inline-never-cold.md +0 -181
  167. package/template/agent/skills/rust-developer/references/rust-rules/opt-inline-small.md +0 -160
  168. package/template/agent/skills/rust-developer/references/rust-rules/opt-likely-hint.md +0 -171
  169. package/template/agent/skills/rust-developer/references/rust-rules/opt-lto-release.md +0 -130
  170. package/template/agent/skills/rust-developer/references/rust-rules/opt-pgo-profile.md +0 -167
  171. package/template/agent/skills/rust-developer/references/rust-rules/opt-simd-portable.md +0 -144
  172. package/template/agent/skills/rust-developer/references/rust-rules/opt-target-cpu.md +0 -154
  173. package/template/agent/skills/rust-developer/references/rust-rules/own-arc-shared.md +0 -141
  174. package/template/agent/skills/rust-developer/references/rust-rules/own-borrow-over-clone.md +0 -95
  175. package/template/agent/skills/rust-developer/references/rust-rules/own-clone-explicit.md +0 -135
  176. package/template/agent/skills/rust-developer/references/rust-rules/own-copy-small.md +0 -124
  177. package/template/agent/skills/rust-developer/references/rust-rules/own-cow-conditional.md +0 -135
  178. package/template/agent/skills/rust-developer/references/rust-rules/own-lifetime-elision.md +0 -134
  179. package/template/agent/skills/rust-developer/references/rust-rules/own-move-large.md +0 -134
  180. package/template/agent/skills/rust-developer/references/rust-rules/own-mutex-interior.md +0 -105
  181. package/template/agent/skills/rust-developer/references/rust-rules/own-rc-single-thread.md +0 -65
  182. package/template/agent/skills/rust-developer/references/rust-rules/own-refcell-interior.md +0 -97
  183. package/template/agent/skills/rust-developer/references/rust-rules/own-rwlock-readers.md +0 -122
  184. package/template/agent/skills/rust-developer/references/rust-rules/own-slice-over-vec.md +0 -119
  185. package/template/agent/skills/rust-developer/references/rust-rules/perf-black-box-bench.md +0 -153
  186. package/template/agent/skills/rust-developer/references/rust-rules/perf-chain-avoid.md +0 -136
  187. package/template/agent/skills/rust-developer/references/rust-rules/perf-collect-into.md +0 -133
  188. package/template/agent/skills/rust-developer/references/rust-rules/perf-collect-once.md +0 -120
  189. package/template/agent/skills/rust-developer/references/rust-rules/perf-drain-reuse.md +0 -137
  190. package/template/agent/skills/rust-developer/references/rust-rules/perf-entry-api.md +0 -134
  191. package/template/agent/skills/rust-developer/references/rust-rules/perf-extend-batch.md +0 -150
  192. package/template/agent/skills/rust-developer/references/rust-rules/perf-iter-lazy.md +0 -123
  193. package/template/agent/skills/rust-developer/references/rust-rules/perf-iter-over-index.md +0 -113
  194. package/template/agent/skills/rust-developer/references/rust-rules/perf-profile-first.md +0 -175
  195. package/template/agent/skills/rust-developer/references/rust-rules/perf-release-profile.md +0 -149
  196. package/template/agent/skills/rust-developer/references/rust-rules/proj-bin-dir.md +0 -142
  197. package/template/agent/skills/rust-developer/references/rust-rules/proj-flat-small.md +0 -133
  198. package/template/agent/skills/rust-developer/references/rust-rules/proj-lib-main-split.md +0 -148
  199. package/template/agent/skills/rust-developer/references/rust-rules/proj-mod-by-feature.md +0 -130
  200. package/template/agent/skills/rust-developer/references/rust-rules/proj-mod-rs-dir.md +0 -120
  201. package/template/agent/skills/rust-developer/references/rust-rules/proj-prelude-module.md +0 -155
  202. package/template/agent/skills/rust-developer/references/rust-rules/proj-pub-crate-internal.md +0 -139
  203. package/template/agent/skills/rust-developer/references/rust-rules/proj-pub-super-parent.md +0 -135
  204. package/template/agent/skills/rust-developer/references/rust-rules/proj-pub-use-reexport.md +0 -162
  205. package/template/agent/skills/rust-developer/references/rust-rules/proj-workspace-deps.md +0 -186
  206. package/template/agent/skills/rust-developer/references/rust-rules/proj-workspace-large.md +0 -162
  207. package/template/agent/skills/rust-developer/references/rust-rules/test-arrange-act-assert.md +0 -160
  208. package/template/agent/skills/rust-developer/references/rust-rules/test-cfg-test-module.md +0 -151
  209. package/template/agent/skills/rust-developer/references/rust-rules/test-criterion-bench.md +0 -171
  210. package/template/agent/skills/rust-developer/references/rust-rules/test-descriptive-names.md +0 -142
  211. package/template/agent/skills/rust-developer/references/rust-rules/test-doctest-examples.md +0 -168
  212. package/template/agent/skills/rust-developer/references/rust-rules/test-fixture-raii.md +0 -151
  213. package/template/agent/skills/rust-developer/references/rust-rules/test-integration-dir.md +0 -144
  214. package/template/agent/skills/rust-developer/references/rust-rules/test-mock-traits.md +0 -189
  215. package/template/agent/skills/rust-developer/references/rust-rules/test-mockall-mocking.md +0 -226
  216. package/template/agent/skills/rust-developer/references/rust-rules/test-proptest-properties.md +0 -161
  217. package/template/agent/skills/rust-developer/references/rust-rules/test-should-panic.md +0 -130
  218. package/template/agent/skills/rust-developer/references/rust-rules/test-tokio-async.md +0 -154
  219. package/template/agent/skills/rust-developer/references/rust-rules/test-use-super.md +0 -127
  220. package/template/agent/skills/rust-developer/references/rust-rules/type-enum-states.md +0 -154
  221. package/template/agent/skills/rust-developer/references/rust-rules/type-generic-bounds.md +0 -142
  222. package/template/agent/skills/rust-developer/references/rust-rules/type-never-diverge.md +0 -146
  223. package/template/agent/skills/rust-developer/references/rust-rules/type-newtype-ids.md +0 -160
  224. package/template/agent/skills/rust-developer/references/rust-rules/type-newtype-validated.md +0 -159
  225. package/template/agent/skills/rust-developer/references/rust-rules/type-no-stringly.md +0 -144
  226. package/template/agent/skills/rust-developer/references/rust-rules/type-option-nullable.md +0 -137
  227. package/template/agent/skills/rust-developer/references/rust-rules/type-phantom-marker.md +0 -188
  228. package/template/agent/skills/rust-developer/references/rust-rules/type-repr-transparent.md +0 -143
  229. package/template/agent/skills/rust-developer/references/rust-rules/type-result-fallible.md +0 -131
  230. package/template/agent/skills/saas-architect/SKILL.md +0 -139
  231. package/template/agent/skills/security-engineer/SKILL.md +0 -133
  232. package/template/agent/skills/seo-specialist/SKILL.md +0 -130
  233. 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