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,185 +0,0 @@
1
- # async-broadcast-pubsub
2
-
3
- > Use `broadcast` channel for pub/sub where all subscribers receive all messages
4
-
5
- ## Why It Matters
6
-
7
- Unlike `mpsc` where one consumer receives each message, `broadcast` delivers each message to all subscribers. This is ideal for event broadcasting, real-time notifications, or when multiple components need to react to the same events independently.
8
-
9
- ## Bad
10
-
11
- ```rust
12
- use tokio::sync::mpsc;
13
-
14
- // mpsc only delivers to ONE consumer
15
- let (tx, mut rx) = mpsc::channel::<Event>(100);
16
-
17
- // Only one of these receives each message!
18
- let mut rx2 = ???; // Can't clone receiver
19
- ```
20
-
21
- ## Good
22
-
23
- ```rust
24
- use tokio::sync::broadcast;
25
-
26
- // broadcast delivers to ALL subscribers
27
- let (tx, _) = broadcast::channel::<Event>(100);
28
-
29
- // Each subscriber gets ALL messages
30
- let mut rx1 = tx.subscribe();
31
- let mut rx2 = tx.subscribe();
32
-
33
- tokio::spawn(async move {
34
- while let Ok(event) = rx1.recv().await {
35
- handle_in_logger(event);
36
- }
37
- });
38
-
39
- tokio::spawn(async move {
40
- while let Ok(event) = rx2.recv().await {
41
- handle_in_metrics(event);
42
- }
43
- });
44
-
45
- // Both subscribers receive this
46
- tx.send(Event::UserLogin { user_id: 42 })?;
47
- ```
48
-
49
- ## Broadcast Semantics
50
-
51
- ```rust
52
- use tokio::sync::broadcast;
53
-
54
- let (tx, mut rx1) = broadcast::channel::<i32>(16);
55
- let mut rx2 = tx.subscribe();
56
-
57
- tx.send(1)?;
58
- tx.send(2)?;
59
-
60
- // Both receive all messages
61
- assert_eq!(rx1.recv().await?, 1);
62
- assert_eq!(rx1.recv().await?, 2);
63
- assert_eq!(rx2.recv().await?, 1);
64
- assert_eq!(rx2.recv().await?, 2);
65
- ```
66
-
67
- ## Handling Lagging Receivers
68
-
69
- ```rust
70
- use tokio::sync::broadcast::{self, error::RecvError};
71
-
72
- let (tx, mut rx) = broadcast::channel::<Event>(16);
73
-
74
- loop {
75
- match rx.recv().await {
76
- Ok(event) => {
77
- process(event);
78
- }
79
- Err(RecvError::Lagged(count)) => {
80
- // Receiver couldn't keep up, missed `count` messages
81
- log::warn!("Missed {} events", count);
82
- // Continue receiving new messages
83
- }
84
- Err(RecvError::Closed) => {
85
- break; // All senders dropped
86
- }
87
- }
88
- }
89
- ```
90
-
91
- ## Event Bus Pattern
92
-
93
- ```rust
94
- use tokio::sync::broadcast;
95
-
96
- #[derive(Clone, Debug)]
97
- enum AppEvent {
98
- UserLoggedIn { user_id: u64 },
99
- OrderCreated { order_id: u64 },
100
- SystemShutdown,
101
- }
102
-
103
- struct EventBus {
104
- tx: broadcast::Sender<AppEvent>,
105
- }
106
-
107
- impl EventBus {
108
- fn new() -> Self {
109
- let (tx, _) = broadcast::channel(1000);
110
- EventBus { tx }
111
- }
112
-
113
- fn publish(&self, event: AppEvent) {
114
- // Ignore error if no subscribers
115
- let _ = self.tx.send(event);
116
- }
117
-
118
- fn subscribe(&self) -> broadcast::Receiver<AppEvent> {
119
- self.tx.subscribe()
120
- }
121
- }
122
-
123
- // Usage
124
- let bus = EventBus::new();
125
-
126
- // Logger subscribes
127
- let mut log_rx = bus.subscribe();
128
- tokio::spawn(async move {
129
- while let Ok(event) = log_rx.recv().await {
130
- log::info!("Event: {:?}", event);
131
- }
132
- });
133
-
134
- // Metrics subscribes
135
- let mut metrics_rx = bus.subscribe();
136
- tokio::spawn(async move {
137
- while let Ok(event) = metrics_rx.recv().await {
138
- record_metric(&event);
139
- }
140
- });
141
-
142
- // Publish events
143
- bus.publish(AppEvent::UserLoggedIn { user_id: 42 });
144
- ```
145
-
146
- ## Broadcast vs Watch
147
-
148
- ```rust
149
- // broadcast: subscribers get ALL messages
150
- // Good for: events, logs, notifications
151
- let (tx, _) = broadcast::channel::<Event>(100);
152
-
153
- // watch: subscribers get LATEST value only
154
- // Good for: config changes, state updates
155
- let (tx, _) = watch::channel(initial_state);
156
-
157
- // If subscriber is slow:
158
- // - broadcast: they receive old messages (or lag)
159
- // - watch: they skip to latest (no history)
160
- ```
161
-
162
- ## Clone Requirement
163
-
164
- ```rust
165
- // broadcast requires Clone because message is cloned to each receiver
166
- use tokio::sync::broadcast;
167
-
168
- #[derive(Clone)] // Required for broadcast
169
- struct Event {
170
- data: String,
171
- }
172
-
173
- let (tx, _) = broadcast::channel::<Event>(100);
174
-
175
- // For non-Clone types, wrap in Arc
176
- use std::sync::Arc;
177
-
178
- let (tx, _) = broadcast::channel::<Arc<LargeNonClone>>(100);
179
- ```
180
-
181
- ## See Also
182
-
183
- - [async-mpsc-queue](./async-mpsc-queue.md) - Single-consumer channels
184
- - [async-watch-latest](./async-watch-latest.md) - Latest-value only
185
- - [async-bounded-channel](./async-bounded-channel.md) - Buffer sizing
@@ -1,203 +0,0 @@
1
- # async-cancellation-token
2
-
3
- > Use `CancellationToken` for graceful shutdown and task cancellation
4
-
5
- ## Why It Matters
6
-
7
- Dropping a `JoinHandle` doesn't cancel the task—it just detaches it. For graceful shutdown, you need explicit cancellation. `tokio_util::sync::CancellationToken` provides a cooperative cancellation mechanism that tasks can check and respond to, enabling clean resource cleanup.
8
-
9
- ## Bad
10
-
11
- ```rust
12
- // Dropping handle doesn't stop the task
13
- let handle = tokio::spawn(async {
14
- loop {
15
- do_work().await;
16
- }
17
- });
18
-
19
- drop(handle); // Task continues running in background!
20
-
21
- // Using bool flag - not async-aware
22
- let running = Arc::new(AtomicBool::new(true));
23
-
24
- tokio::spawn({
25
- let running = running.clone();
26
- async move {
27
- while running.load(Ordering::Relaxed) {
28
- do_work().await; // Can't wake up if blocked here
29
- }
30
- }
31
- });
32
-
33
- running.store(false, Ordering::Relaxed);
34
- // Task won't stop until current do_work() completes
35
- ```
36
-
37
- ## Good
38
-
39
- ```rust
40
- use tokio_util::sync::CancellationToken;
41
-
42
- let token = CancellationToken::new();
43
-
44
- let handle = tokio::spawn({
45
- let token = token.clone();
46
- async move {
47
- loop {
48
- tokio::select! {
49
- _ = token.cancelled() => {
50
- println!("Shutting down gracefully");
51
- cleanup().await;
52
- break;
53
- }
54
- _ = do_work() => {
55
- // Work completed
56
- }
57
- }
58
- }
59
- }
60
- });
61
-
62
- // Later: trigger cancellation
63
- token.cancel();
64
- handle.await?; // Task completes cleanly
65
- ```
66
-
67
- ## CancellationToken API
68
-
69
- ```rust
70
- use tokio_util::sync::CancellationToken;
71
-
72
- // Create token
73
- let token = CancellationToken::new();
74
-
75
- // Clone for sharing (cheap Arc-based clone)
76
- let token2 = token.clone();
77
-
78
- // Check if cancelled (non-blocking)
79
- if token.is_cancelled() {
80
- return;
81
- }
82
-
83
- // Wait for cancellation (async)
84
- token.cancelled().await;
85
-
86
- // Trigger cancellation
87
- token.cancel();
88
-
89
- // Child tokens - cancelled when parent is cancelled
90
- let child = token.child_token();
91
- ```
92
-
93
- ## Hierarchical Cancellation
94
-
95
- ```rust
96
- async fn run_server(shutdown: CancellationToken) {
97
- let listener = TcpListener::bind("0.0.0.0:8080").await?;
98
-
99
- loop {
100
- tokio::select! {
101
- _ = shutdown.cancelled() => {
102
- println!("Server shutting down");
103
- break;
104
- }
105
- result = listener.accept() => {
106
- let (socket, _) = result?;
107
- // Each connection gets child token
108
- let conn_token = shutdown.child_token();
109
- tokio::spawn(handle_connection(socket, conn_token));
110
- }
111
- }
112
- }
113
-
114
- // Child tokens auto-cancelled when we exit
115
- }
116
-
117
- async fn handle_connection(socket: TcpStream, token: CancellationToken) {
118
- loop {
119
- tokio::select! {
120
- _ = token.cancelled() => {
121
- // Connection cleanup
122
- break;
123
- }
124
- data = socket.read() => {
125
- // Handle data
126
- }
127
- }
128
- }
129
- }
130
- ```
131
-
132
- ## Graceful Shutdown Pattern
133
-
134
- ```rust
135
- use tokio::signal;
136
-
137
- async fn main() -> Result<()> {
138
- let shutdown = CancellationToken::new();
139
-
140
- // Spawn signal handler
141
- let shutdown_trigger = shutdown.clone();
142
- tokio::spawn(async move {
143
- signal::ctrl_c().await.expect("failed to listen for Ctrl+C");
144
- println!("Received Ctrl+C, initiating shutdown...");
145
- shutdown_trigger.cancel();
146
- });
147
-
148
- // Run application with shutdown token
149
- run_app(shutdown).await
150
- }
151
-
152
- async fn run_app(shutdown: CancellationToken) -> Result<()> {
153
- let mut tasks = JoinSet::new();
154
-
155
- tasks.spawn(worker_task(shutdown.child_token()));
156
- tasks.spawn(server_task(shutdown.child_token()));
157
-
158
- // Wait for shutdown or task completion
159
- tokio::select! {
160
- _ = shutdown.cancelled() => {
161
- println!("Shutdown requested, waiting for tasks...");
162
- }
163
- Some(result) = tasks.join_next() => {
164
- // A task completed/failed
165
- result??;
166
- }
167
- }
168
-
169
- // Wait for remaining tasks with timeout
170
- tokio::time::timeout(
171
- Duration::from_secs(30),
172
- async { while tasks.join_next().await.is_some() {} }
173
- ).await.ok();
174
-
175
- Ok(())
176
- }
177
- ```
178
-
179
- ## DropGuard Pattern
180
-
181
- ```rust
182
- use tokio_util::sync::CancellationToken;
183
-
184
- // Auto-cancel on drop
185
- let token = CancellationToken::new();
186
- let guard = token.clone().drop_guard();
187
-
188
- tokio::spawn({
189
- let token = token.clone();
190
- async move {
191
- token.cancelled().await;
192
- println!("Cancelled!");
193
- }
194
- });
195
-
196
- drop(guard); // Automatically calls token.cancel()
197
- ```
198
-
199
- ## See Also
200
-
201
- - [async-joinset-structured](./async-joinset-structured.md) - Managing multiple tasks
202
- - [async-select-racing](./async-select-racing.md) - select! for cancellation
203
- - [async-tokio-runtime](./async-tokio-runtime.md) - Runtime shutdown
@@ -1,171 +0,0 @@
1
- # async-clone-before-await
2
-
3
- > Clone Arc/Rc data before await points to avoid holding references across suspension
4
-
5
- ## Why It Matters
6
-
7
- References held across `.await` points extend the future's lifetime and can cause borrow checker issues or prevent `Send` bounds. Cloning `Arc`/`Rc` before the await ensures the future only holds owned data, making it `Send` and avoiding lifetime complications.
8
-
9
- ## Bad
10
-
11
- ```rust
12
- use std::sync::Arc;
13
-
14
- async fn process(data: Arc<Data>) {
15
- // Borrow extends across await - future is not Send
16
- let slice = &data.items[..]; // Borrow of Arc contents
17
-
18
- expensive_async_operation().await; // Await with active borrow
19
-
20
- use_slice(slice); // Still using the borrow
21
- }
22
-
23
- // Error: future cannot be sent between threads safely
24
- // because `&[Item]` cannot be sent between threads safely
25
- tokio::spawn(process(data));
26
- ```
27
-
28
- ## Good
29
-
30
- ```rust
31
- use std::sync::Arc;
32
-
33
- async fn process(data: Arc<Data>) {
34
- // Clone what you need before await
35
- let items = data.items.clone(); // Owned Vec
36
-
37
- expensive_async_operation().await;
38
-
39
- use_items(&items); // Using owned data
40
- }
41
-
42
- // Or clone the Arc itself
43
- async fn share_data(data: Arc<Data>) {
44
- let data = data.clone(); // Another Arc handle
45
-
46
- some_async_work().await;
47
-
48
- process(&data); // Safe - we own the Arc
49
- }
50
- ```
51
-
52
- ## The Send Problem
53
-
54
- ```rust
55
- // Futures must be Send to spawn on multi-threaded runtime
56
- async fn not_send() {
57
- let rc = Rc::new(42); // Rc is !Send
58
-
59
- tokio::time::sleep(Duration::from_secs(1)).await;
60
-
61
- println!("{}", rc); // rc held across await
62
- }
63
-
64
- tokio::spawn(not_send()); // ERROR: future is not Send
65
-
66
- // Fix: use Arc or don't hold across await
67
- async fn is_send() {
68
- let arc = Arc::new(42); // Arc is Send
69
-
70
- tokio::time::sleep(Duration::from_secs(1)).await;
71
-
72
- println!("{}", arc);
73
- }
74
-
75
- tokio::spawn(is_send()); // OK
76
- ```
77
-
78
- ## Minimizing Clones
79
-
80
- ```rust
81
- // Bad: clone everything eagerly
82
- async fn wasteful(data: Arc<LargeData>) {
83
- let data = (*data).clone(); // Clones entire LargeData
84
- async_work().await;
85
- use_one_field(&data.small_field);
86
- }
87
-
88
- // Good: clone only what you need
89
- async fn efficient(data: Arc<LargeData>) {
90
- let small = data.small_field.clone(); // Clone only needed field
91
- async_work().await;
92
- use_one_field(&small);
93
- }
94
-
95
- // Good: if you need the whole thing, keep the Arc
96
- async fn arc_efficient(data: Arc<LargeData>) {
97
- let data = data.clone(); // Cheap Arc clone
98
- async_work().await;
99
- use_data(&data); // Access through Arc
100
- }
101
- ```
102
-
103
- ## Spawn Pattern
104
-
105
- ```rust
106
- // Common pattern: clone for spawned task
107
- let shared = Arc::new(SharedState::new());
108
-
109
- for i in 0..10 {
110
- let shared = shared.clone(); // Clone before moving into spawn
111
- tokio::spawn(async move {
112
- // Task owns its Arc clone
113
- shared.do_something(i).await;
114
- });
115
- }
116
- ```
117
-
118
- ## Scope-Based Approach
119
-
120
- ```rust
121
- // Limit borrow scope to before await
122
- async fn scoped(data: Arc<Data>) {
123
- // Scope 1: borrow, compute, drop borrow
124
- let computed = {
125
- let slice = &data.items[..]; // Borrow
126
- compute_something(slice) // Use
127
- }; // Borrow ends here
128
-
129
- // Now safe to await
130
- expensive_async_operation().await;
131
-
132
- use_computed(computed);
133
- }
134
- ```
135
-
136
- ## MutexGuard Across Await
137
-
138
- ```rust
139
- use tokio::sync::Mutex;
140
-
141
- // BAD: holding guard across await
142
- async fn bad(mutex: Arc<Mutex<Data>>) {
143
- let mut guard = mutex.lock().await;
144
- guard.value += 1;
145
-
146
- slow_operation().await; // Guard held during await!
147
-
148
- guard.value += 1;
149
- }
150
-
151
- // GOOD: release before await
152
- async fn good(mutex: Arc<Mutex<Data>>) {
153
- {
154
- let mut guard = mutex.lock().await;
155
- guard.value += 1;
156
- } // Guard released
157
-
158
- slow_operation().await;
159
-
160
- {
161
- let mut guard = mutex.lock().await;
162
- guard.value += 1;
163
- }
164
- }
165
- ```
166
-
167
- ## See Also
168
-
169
- - [async-no-lock-await](./async-no-lock-await.md) - Lock guards across await
170
- - [own-arc-shared](./own-arc-shared.md) - Arc usage patterns
171
- - [async-spawn-blocking](./async-spawn-blocking.md) - Blocking in async
@@ -1,158 +0,0 @@
1
- # async-join-parallel
2
-
3
- > Use `join!` or `try_join!` for concurrent independent futures
4
-
5
- ## Why It Matters
6
-
7
- Awaiting futures sequentially takes the sum of their durations. `join!` runs futures concurrently, taking only as long as the slowest one. For independent operations like multiple API calls or parallel file reads, this can dramatically reduce latency.
8
-
9
- ## Bad
10
-
11
- ```rust
12
- async fn fetch_data() -> (User, Posts, Comments) {
13
- // Sequential: 300ms total (100 + 100 + 100)
14
- let user = fetch_user().await; // 100ms
15
- let posts = fetch_posts().await; // 100ms
16
- let comments = fetch_comments().await; // 100ms
17
-
18
- (user, posts, comments)
19
- }
20
-
21
- async fn read_configs() -> Result<(Config, Settings)> {
22
- // Sequential: 20ms + 20ms = 40ms
23
- let config = fs::read_to_string("config.toml").await?;
24
- let settings = fs::read_to_string("settings.json").await?;
25
-
26
- Ok((parse_config(&config)?, parse_settings(&settings)?))
27
- }
28
- ```
29
-
30
- ## Good
31
-
32
- ```rust
33
- use tokio::join;
34
-
35
- async fn fetch_data() -> (User, Posts, Comments) {
36
- // Concurrent: ~100ms total (max of all three)
37
- let (user, posts, comments) = join!(
38
- fetch_user(),
39
- fetch_posts(),
40
- fetch_comments(),
41
- );
42
-
43
- (user, posts, comments)
44
- }
45
-
46
- use tokio::try_join;
47
-
48
- async fn read_configs() -> Result<(Config, Settings)> {
49
- // Concurrent: ~20ms total
50
- let (config_str, settings_str) = try_join!(
51
- fs::read_to_string("config.toml"),
52
- fs::read_to_string("settings.json"),
53
- )?;
54
-
55
- Ok((parse_config(&config_str)?, parse_settings(&settings_str)?))
56
- }
57
- ```
58
-
59
- ## join! vs try_join!
60
-
61
- ```rust
62
- // join! - all futures run to completion, returns tuple
63
- let (a, b, c) = join!(future_a, future_b, future_c);
64
-
65
- // try_join! - short-circuits on first error
66
- let (a, b, c) = try_join!(fallible_a, fallible_b, fallible_c)?;
67
- // If fallible_b fails, returns Err immediately
68
- // Other futures may still be running (cancellation is async)
69
- ```
70
-
71
- ## futures::join_all for Dynamic Collections
72
-
73
- ```rust
74
- use futures::future::join_all;
75
-
76
- async fn fetch_all_users(ids: &[u64]) -> Vec<User> {
77
- let futures: Vec<_> = ids.iter()
78
- .map(|id| fetch_user(*id))
79
- .collect();
80
-
81
- join_all(futures).await
82
- }
83
-
84
- // With fallible futures
85
- use futures::future::try_join_all;
86
-
87
- async fn fetch_all_users(ids: &[u64]) -> Result<Vec<User>> {
88
- let futures: Vec<_> = ids.iter()
89
- .map(|id| fetch_user(*id))
90
- .collect();
91
-
92
- try_join_all(futures).await
93
- }
94
- ```
95
-
96
- ## Limiting Concurrency
97
-
98
- ```rust
99
- use futures::stream::{self, StreamExt};
100
-
101
- async fn fetch_with_limit(ids: &[u64]) -> Vec<Result<User>> {
102
- stream::iter(ids)
103
- .map(|id| fetch_user(*id))
104
- .buffer_unordered(10) // Max 10 concurrent requests
105
- .collect()
106
- .await
107
- }
108
-
109
- // Or with tokio::sync::Semaphore
110
- use tokio::sync::Semaphore;
111
-
112
- async fn fetch_with_semaphore(ids: &[u64]) -> Vec<User> {
113
- let semaphore = Arc::new(Semaphore::new(10));
114
-
115
- let futures: Vec<_> = ids.iter().map(|id| {
116
- let semaphore = semaphore.clone();
117
- async move {
118
- let _permit = semaphore.acquire().await.unwrap();
119
- fetch_user(*id).await
120
- }
121
- }).collect();
122
-
123
- join_all(futures).await
124
- }
125
- ```
126
-
127
- ## When NOT to Use join!
128
-
129
- ```rust
130
- // ❌ Dependent futures - must be sequential
131
- async fn create_and_populate() -> Result<()> {
132
- let db = create_database().await?; // Must complete first
133
- populate_tables(&db).await?; // Depends on db
134
- Ok(())
135
- }
136
-
137
- // ❌ Short-circuiting logic
138
- async fn find_first() -> Option<Data> {
139
- // Want to stop when one succeeds
140
- // Use select! instead
141
- }
142
-
143
- // ❌ Shared mutable state
144
- async fn bad_shared_state() {
145
- let counter = Arc::new(Mutex::new(0));
146
- // This might work but can cause contention
147
- join!(
148
- increment(counter.clone()),
149
- increment(counter.clone()),
150
- );
151
- }
152
- ```
153
-
154
- ## See Also
155
-
156
- - [async-try-join](./async-try-join.md) - Error handling in concurrent futures
157
- - [async-select-racing](./async-select-racing.md) - Racing futures
158
- - [async-joinset-structured](./async-joinset-structured.md) - Dynamic task sets