agy-superpowers 5.1.4 → 5.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (185) hide show
  1. package/package.json +1 -1
  2. package/template/agent/rules/debug-confirmation-policy.md +34 -0
  3. package/template/agent/rules/language-matching.md +32 -0
  4. package/template/agent/skills/rust-developer/SKILL.md +281 -0
  5. package/template/agent/skills/rust-developer/references/rust-rules/_sections.md +231 -0
  6. package/template/agent/skills/rust-developer/references/rust-rules/anti-clone-excessive.md +124 -0
  7. package/template/agent/skills/rust-developer/references/rust-rules/anti-collect-intermediate.md +131 -0
  8. package/template/agent/skills/rust-developer/references/rust-rules/anti-empty-catch.md +132 -0
  9. package/template/agent/skills/rust-developer/references/rust-rules/anti-expect-lazy.md +95 -0
  10. package/template/agent/skills/rust-developer/references/rust-rules/anti-format-hot-path.md +141 -0
  11. package/template/agent/skills/rust-developer/references/rust-rules/anti-index-over-iter.md +125 -0
  12. package/template/agent/skills/rust-developer/references/rust-rules/anti-lock-across-await.md +127 -0
  13. package/template/agent/skills/rust-developer/references/rust-rules/anti-over-abstraction.md +120 -0
  14. package/template/agent/skills/rust-developer/references/rust-rules/anti-panic-expected.md +131 -0
  15. package/template/agent/skills/rust-developer/references/rust-rules/anti-premature-optimize.md +156 -0
  16. package/template/agent/skills/rust-developer/references/rust-rules/anti-string-for-str.md +122 -0
  17. package/template/agent/skills/rust-developer/references/rust-rules/anti-stringly-typed.md +167 -0
  18. package/template/agent/skills/rust-developer/references/rust-rules/anti-type-erasure.md +134 -0
  19. package/template/agent/skills/rust-developer/references/rust-rules/anti-unwrap-abuse.md +143 -0
  20. package/template/agent/skills/rust-developer/references/rust-rules/anti-vec-for-slice.md +121 -0
  21. package/template/agent/skills/rust-developer/references/rust-rules/api-builder-must-use.md +143 -0
  22. package/template/agent/skills/rust-developer/references/rust-rules/api-builder-pattern.md +187 -0
  23. package/template/agent/skills/rust-developer/references/rust-rules/api-common-traits.md +165 -0
  24. package/template/agent/skills/rust-developer/references/rust-rules/api-default-impl.md +177 -0
  25. package/template/agent/skills/rust-developer/references/rust-rules/api-extension-trait.md +163 -0
  26. package/template/agent/skills/rust-developer/references/rust-rules/api-from-not-into.md +146 -0
  27. package/template/agent/skills/rust-developer/references/rust-rules/api-impl-asref.md +142 -0
  28. package/template/agent/skills/rust-developer/references/rust-rules/api-impl-into.md +160 -0
  29. package/template/agent/skills/rust-developer/references/rust-rules/api-must-use.md +125 -0
  30. package/template/agent/skills/rust-developer/references/rust-rules/api-newtype-safety.md +162 -0
  31. package/template/agent/skills/rust-developer/references/rust-rules/api-non-exhaustive.md +177 -0
  32. package/template/agent/skills/rust-developer/references/rust-rules/api-parse-dont-validate.md +184 -0
  33. package/template/agent/skills/rust-developer/references/rust-rules/api-sealed-trait.md +168 -0
  34. package/template/agent/skills/rust-developer/references/rust-rules/api-serde-optional.md +182 -0
  35. package/template/agent/skills/rust-developer/references/rust-rules/api-typestate.md +199 -0
  36. package/template/agent/skills/rust-developer/references/rust-rules/async-bounded-channel.md +175 -0
  37. package/template/agent/skills/rust-developer/references/rust-rules/async-broadcast-pubsub.md +185 -0
  38. package/template/agent/skills/rust-developer/references/rust-rules/async-cancellation-token.md +203 -0
  39. package/template/agent/skills/rust-developer/references/rust-rules/async-clone-before-await.md +171 -0
  40. package/template/agent/skills/rust-developer/references/rust-rules/async-join-parallel.md +158 -0
  41. package/template/agent/skills/rust-developer/references/rust-rules/async-joinset-structured.md +195 -0
  42. package/template/agent/skills/rust-developer/references/rust-rules/async-mpsc-queue.md +171 -0
  43. package/template/agent/skills/rust-developer/references/rust-rules/async-no-lock-await.md +156 -0
  44. package/template/agent/skills/rust-developer/references/rust-rules/async-oneshot-response.md +191 -0
  45. package/template/agent/skills/rust-developer/references/rust-rules/async-select-racing.md +198 -0
  46. package/template/agent/skills/rust-developer/references/rust-rules/async-spawn-blocking.md +154 -0
  47. package/template/agent/skills/rust-developer/references/rust-rules/async-tokio-fs.md +167 -0
  48. package/template/agent/skills/rust-developer/references/rust-rules/async-tokio-runtime.md +169 -0
  49. package/template/agent/skills/rust-developer/references/rust-rules/async-try-join.md +172 -0
  50. package/template/agent/skills/rust-developer/references/rust-rules/async-watch-latest.md +189 -0
  51. package/template/agent/skills/rust-developer/references/rust-rules/doc-all-public.md +113 -0
  52. package/template/agent/skills/rust-developer/references/rust-rules/doc-cargo-metadata.md +147 -0
  53. package/template/agent/skills/rust-developer/references/rust-rules/doc-errors-section.md +122 -0
  54. package/template/agent/skills/rust-developer/references/rust-rules/doc-examples-section.md +161 -0
  55. package/template/agent/skills/rust-developer/references/rust-rules/doc-hidden-setup.md +149 -0
  56. package/template/agent/skills/rust-developer/references/rust-rules/doc-intra-links.md +138 -0
  57. package/template/agent/skills/rust-developer/references/rust-rules/doc-link-types.md +169 -0
  58. package/template/agent/skills/rust-developer/references/rust-rules/doc-module-inner.md +116 -0
  59. package/template/agent/skills/rust-developer/references/rust-rules/doc-panics-section.md +128 -0
  60. package/template/agent/skills/rust-developer/references/rust-rules/doc-question-mark.md +136 -0
  61. package/template/agent/skills/rust-developer/references/rust-rules/doc-safety-section.md +131 -0
  62. package/template/agent/skills/rust-developer/references/rust-rules/err-anyhow-app.md +179 -0
  63. package/template/agent/skills/rust-developer/references/rust-rules/err-context-chain.md +144 -0
  64. package/template/agent/skills/rust-developer/references/rust-rules/err-custom-type.md +152 -0
  65. package/template/agent/skills/rust-developer/references/rust-rules/err-doc-errors.md +145 -0
  66. package/template/agent/skills/rust-developer/references/rust-rules/err-expect-bugs-only.md +133 -0
  67. package/template/agent/skills/rust-developer/references/rust-rules/err-from-impl.md +152 -0
  68. package/template/agent/skills/rust-developer/references/rust-rules/err-lowercase-msg.md +124 -0
  69. package/template/agent/skills/rust-developer/references/rust-rules/err-no-unwrap-prod.md +115 -0
  70. package/template/agent/skills/rust-developer/references/rust-rules/err-question-mark.md +151 -0
  71. package/template/agent/skills/rust-developer/references/rust-rules/err-result-over-panic.md +130 -0
  72. package/template/agent/skills/rust-developer/references/rust-rules/err-source-chain.md +155 -0
  73. package/template/agent/skills/rust-developer/references/rust-rules/err-thiserror-lib.md +171 -0
  74. package/template/agent/skills/rust-developer/references/rust-rules/lint-cargo-metadata.md +138 -0
  75. package/template/agent/skills/rust-developer/references/rust-rules/lint-deny-correctness.md +107 -0
  76. package/template/agent/skills/rust-developer/references/rust-rules/lint-missing-docs.md +154 -0
  77. package/template/agent/skills/rust-developer/references/rust-rules/lint-pedantic-selective.md +118 -0
  78. package/template/agent/skills/rust-developer/references/rust-rules/lint-rustfmt-check.md +157 -0
  79. package/template/agent/skills/rust-developer/references/rust-rules/lint-unsafe-doc.md +133 -0
  80. package/template/agent/skills/rust-developer/references/rust-rules/lint-warn-complexity.md +131 -0
  81. package/template/agent/skills/rust-developer/references/rust-rules/lint-warn-perf.md +136 -0
  82. package/template/agent/skills/rust-developer/references/rust-rules/lint-warn-style.md +135 -0
  83. package/template/agent/skills/rust-developer/references/rust-rules/lint-warn-suspicious.md +122 -0
  84. package/template/agent/skills/rust-developer/references/rust-rules/lint-workspace-lints.md +172 -0
  85. package/template/agent/skills/rust-developer/references/rust-rules/mem-arena-allocator.md +168 -0
  86. package/template/agent/skills/rust-developer/references/rust-rules/mem-arrayvec.md +142 -0
  87. package/template/agent/skills/rust-developer/references/rust-rules/mem-assert-type-size.md +168 -0
  88. package/template/agent/skills/rust-developer/references/rust-rules/mem-avoid-format.md +147 -0
  89. package/template/agent/skills/rust-developer/references/rust-rules/mem-box-large-variant.md +158 -0
  90. package/template/agent/skills/rust-developer/references/rust-rules/mem-boxed-slice.md +139 -0
  91. package/template/agent/skills/rust-developer/references/rust-rules/mem-clone-from.md +147 -0
  92. package/template/agent/skills/rust-developer/references/rust-rules/mem-compact-string.md +149 -0
  93. package/template/agent/skills/rust-developer/references/rust-rules/mem-reuse-collections.md +174 -0
  94. package/template/agent/skills/rust-developer/references/rust-rules/mem-smaller-integers.md +159 -0
  95. package/template/agent/skills/rust-developer/references/rust-rules/mem-smallvec.md +138 -0
  96. package/template/agent/skills/rust-developer/references/rust-rules/mem-thinvec.md +142 -0
  97. package/template/agent/skills/rust-developer/references/rust-rules/mem-with-capacity.md +156 -0
  98. package/template/agent/skills/rust-developer/references/rust-rules/mem-write-over-format.md +172 -0
  99. package/template/agent/skills/rust-developer/references/rust-rules/mem-zero-copy.md +164 -0
  100. package/template/agent/skills/rust-developer/references/rust-rules/name-acronym-word.md +99 -0
  101. package/template/agent/skills/rust-developer/references/rust-rules/name-as-free.md +104 -0
  102. package/template/agent/skills/rust-developer/references/rust-rules/name-consts-screaming.md +94 -0
  103. package/template/agent/skills/rust-developer/references/rust-rules/name-crate-no-rs.md +78 -0
  104. package/template/agent/skills/rust-developer/references/rust-rules/name-funcs-snake.md +76 -0
  105. package/template/agent/skills/rust-developer/references/rust-rules/name-into-ownership.md +123 -0
  106. package/template/agent/skills/rust-developer/references/rust-rules/name-is-has-bool.md +127 -0
  107. package/template/agent/skills/rust-developer/references/rust-rules/name-iter-convention.md +129 -0
  108. package/template/agent/skills/rust-developer/references/rust-rules/name-iter-method.md +131 -0
  109. package/template/agent/skills/rust-developer/references/rust-rules/name-iter-type-match.md +142 -0
  110. package/template/agent/skills/rust-developer/references/rust-rules/name-lifetime-short.md +86 -0
  111. package/template/agent/skills/rust-developer/references/rust-rules/name-no-get-prefix.md +154 -0
  112. package/template/agent/skills/rust-developer/references/rust-rules/name-to-expensive.md +118 -0
  113. package/template/agent/skills/rust-developer/references/rust-rules/name-type-param-single.md +92 -0
  114. package/template/agent/skills/rust-developer/references/rust-rules/name-types-camel.md +65 -0
  115. package/template/agent/skills/rust-developer/references/rust-rules/name-variants-camel.md +101 -0
  116. package/template/agent/skills/rust-developer/references/rust-rules/opt-bounds-check.md +161 -0
  117. package/template/agent/skills/rust-developer/references/rust-rules/opt-cache-friendly.md +187 -0
  118. package/template/agent/skills/rust-developer/references/rust-rules/opt-codegen-units.md +142 -0
  119. package/template/agent/skills/rust-developer/references/rust-rules/opt-cold-unlikely.md +152 -0
  120. package/template/agent/skills/rust-developer/references/rust-rules/opt-inline-always-rare.md +141 -0
  121. package/template/agent/skills/rust-developer/references/rust-rules/opt-inline-never-cold.md +181 -0
  122. package/template/agent/skills/rust-developer/references/rust-rules/opt-inline-small.md +160 -0
  123. package/template/agent/skills/rust-developer/references/rust-rules/opt-likely-hint.md +171 -0
  124. package/template/agent/skills/rust-developer/references/rust-rules/opt-lto-release.md +130 -0
  125. package/template/agent/skills/rust-developer/references/rust-rules/opt-pgo-profile.md +167 -0
  126. package/template/agent/skills/rust-developer/references/rust-rules/opt-simd-portable.md +144 -0
  127. package/template/agent/skills/rust-developer/references/rust-rules/opt-target-cpu.md +154 -0
  128. package/template/agent/skills/rust-developer/references/rust-rules/own-arc-shared.md +141 -0
  129. package/template/agent/skills/rust-developer/references/rust-rules/own-borrow-over-clone.md +95 -0
  130. package/template/agent/skills/rust-developer/references/rust-rules/own-clone-explicit.md +135 -0
  131. package/template/agent/skills/rust-developer/references/rust-rules/own-copy-small.md +124 -0
  132. package/template/agent/skills/rust-developer/references/rust-rules/own-cow-conditional.md +135 -0
  133. package/template/agent/skills/rust-developer/references/rust-rules/own-lifetime-elision.md +134 -0
  134. package/template/agent/skills/rust-developer/references/rust-rules/own-move-large.md +134 -0
  135. package/template/agent/skills/rust-developer/references/rust-rules/own-mutex-interior.md +105 -0
  136. package/template/agent/skills/rust-developer/references/rust-rules/own-rc-single-thread.md +65 -0
  137. package/template/agent/skills/rust-developer/references/rust-rules/own-refcell-interior.md +97 -0
  138. package/template/agent/skills/rust-developer/references/rust-rules/own-rwlock-readers.md +122 -0
  139. package/template/agent/skills/rust-developer/references/rust-rules/own-slice-over-vec.md +119 -0
  140. package/template/agent/skills/rust-developer/references/rust-rules/perf-black-box-bench.md +153 -0
  141. package/template/agent/skills/rust-developer/references/rust-rules/perf-chain-avoid.md +136 -0
  142. package/template/agent/skills/rust-developer/references/rust-rules/perf-collect-into.md +133 -0
  143. package/template/agent/skills/rust-developer/references/rust-rules/perf-collect-once.md +120 -0
  144. package/template/agent/skills/rust-developer/references/rust-rules/perf-drain-reuse.md +137 -0
  145. package/template/agent/skills/rust-developer/references/rust-rules/perf-entry-api.md +134 -0
  146. package/template/agent/skills/rust-developer/references/rust-rules/perf-extend-batch.md +150 -0
  147. package/template/agent/skills/rust-developer/references/rust-rules/perf-iter-lazy.md +123 -0
  148. package/template/agent/skills/rust-developer/references/rust-rules/perf-iter-over-index.md +113 -0
  149. package/template/agent/skills/rust-developer/references/rust-rules/perf-profile-first.md +175 -0
  150. package/template/agent/skills/rust-developer/references/rust-rules/perf-release-profile.md +149 -0
  151. package/template/agent/skills/rust-developer/references/rust-rules/proj-bin-dir.md +142 -0
  152. package/template/agent/skills/rust-developer/references/rust-rules/proj-flat-small.md +133 -0
  153. package/template/agent/skills/rust-developer/references/rust-rules/proj-lib-main-split.md +148 -0
  154. package/template/agent/skills/rust-developer/references/rust-rules/proj-mod-by-feature.md +130 -0
  155. package/template/agent/skills/rust-developer/references/rust-rules/proj-mod-rs-dir.md +120 -0
  156. package/template/agent/skills/rust-developer/references/rust-rules/proj-prelude-module.md +155 -0
  157. package/template/agent/skills/rust-developer/references/rust-rules/proj-pub-crate-internal.md +139 -0
  158. package/template/agent/skills/rust-developer/references/rust-rules/proj-pub-super-parent.md +135 -0
  159. package/template/agent/skills/rust-developer/references/rust-rules/proj-pub-use-reexport.md +162 -0
  160. package/template/agent/skills/rust-developer/references/rust-rules/proj-workspace-deps.md +186 -0
  161. package/template/agent/skills/rust-developer/references/rust-rules/proj-workspace-large.md +162 -0
  162. package/template/agent/skills/rust-developer/references/rust-rules/test-arrange-act-assert.md +160 -0
  163. package/template/agent/skills/rust-developer/references/rust-rules/test-cfg-test-module.md +151 -0
  164. package/template/agent/skills/rust-developer/references/rust-rules/test-criterion-bench.md +171 -0
  165. package/template/agent/skills/rust-developer/references/rust-rules/test-descriptive-names.md +142 -0
  166. package/template/agent/skills/rust-developer/references/rust-rules/test-doctest-examples.md +168 -0
  167. package/template/agent/skills/rust-developer/references/rust-rules/test-fixture-raii.md +151 -0
  168. package/template/agent/skills/rust-developer/references/rust-rules/test-integration-dir.md +144 -0
  169. package/template/agent/skills/rust-developer/references/rust-rules/test-mock-traits.md +189 -0
  170. package/template/agent/skills/rust-developer/references/rust-rules/test-mockall-mocking.md +226 -0
  171. package/template/agent/skills/rust-developer/references/rust-rules/test-proptest-properties.md +161 -0
  172. package/template/agent/skills/rust-developer/references/rust-rules/test-should-panic.md +130 -0
  173. package/template/agent/skills/rust-developer/references/rust-rules/test-tokio-async.md +154 -0
  174. package/template/agent/skills/rust-developer/references/rust-rules/test-use-super.md +127 -0
  175. package/template/agent/skills/rust-developer/references/rust-rules/type-enum-states.md +154 -0
  176. package/template/agent/skills/rust-developer/references/rust-rules/type-generic-bounds.md +142 -0
  177. package/template/agent/skills/rust-developer/references/rust-rules/type-never-diverge.md +146 -0
  178. package/template/agent/skills/rust-developer/references/rust-rules/type-newtype-ids.md +160 -0
  179. package/template/agent/skills/rust-developer/references/rust-rules/type-newtype-validated.md +159 -0
  180. package/template/agent/skills/rust-developer/references/rust-rules/type-no-stringly.md +144 -0
  181. package/template/agent/skills/rust-developer/references/rust-rules/type-option-nullable.md +137 -0
  182. package/template/agent/skills/rust-developer/references/rust-rules/type-phantom-marker.md +188 -0
  183. package/template/agent/skills/rust-developer/references/rust-rules/type-repr-transparent.md +143 -0
  184. package/template/agent/skills/rust-developer/references/rust-rules/type-result-fallible.md +131 -0
  185. package/template/agent/skills/systematic-debugging/SKILL.md +17 -0
@@ -0,0 +1,156 @@
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
@@ -0,0 +1,191 @@
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
@@ -0,0 +1,198 @@
1
+ # async-select-racing
2
+
3
+ > Use `select!` to race futures and handle the first to complete
4
+
5
+ ## Why It Matters
6
+
7
+ Sometimes you need the first result from multiple futures—timeout vs operation, cancellation vs work, or competing alternatives. `tokio::select!` lets you race futures and handle whichever completes first, while properly cancelling the others.
8
+
9
+ ## Bad
10
+
11
+ ```rust
12
+ // Can't express "whichever finishes first"
13
+ async fn fetch_with_fallback() -> Data {
14
+ match fetch_primary().await {
15
+ Ok(data) => data,
16
+ Err(_) => fetch_fallback().await.unwrap(), // Sequential, not racing
17
+ }
18
+ }
19
+
20
+ // Manual timeout is error-prone
21
+ async fn fetch_with_timeout() -> Option<Data> {
22
+ let start = Instant::now();
23
+ loop {
24
+ if start.elapsed() > Duration::from_secs(5) {
25
+ return None;
26
+ }
27
+ // How do we check timeout while awaiting?
28
+ }
29
+ }
30
+ ```
31
+
32
+ ## Good
33
+
34
+ ```rust
35
+ use tokio::select;
36
+
37
+ async fn fetch_with_timeout() -> Result<Data, Error> {
38
+ select! {
39
+ result = fetch_data() => result,
40
+ _ = tokio::time::sleep(Duration::from_secs(5)) => {
41
+ Err(Error::Timeout)
42
+ }
43
+ }
44
+ }
45
+
46
+ async fn fetch_with_fallback() -> Data {
47
+ select! {
48
+ result = fetch_primary() => {
49
+ match result {
50
+ Ok(data) => data,
51
+ Err(_) => fetch_fallback().await.unwrap()
52
+ }
53
+ }
54
+ _ = tokio::time::sleep(Duration::from_secs(1)) => {
55
+ // Primary too slow, use fallback
56
+ fetch_fallback().await.unwrap()
57
+ }
58
+ }
59
+ }
60
+ ```
61
+
62
+ ## select! Syntax
63
+
64
+ ```rust
65
+ select! {
66
+ // Pattern = future => handler
67
+ result = async_operation() => {
68
+ // Handle result
69
+ println!("Got: {:?}", result);
70
+ }
71
+
72
+ // Can bind with pattern matching
73
+ Ok(data) = fallible_operation() => {
74
+ process(data);
75
+ }
76
+
77
+ // Conditional branches with if guards
78
+ msg = channel.recv(), if should_receive => {
79
+ handle_message(msg);
80
+ }
81
+
82
+ // else branch for when all futures are disabled
83
+ else => {
84
+ println!("All branches disabled");
85
+ }
86
+ }
87
+ ```
88
+
89
+ ## Cancellation Behavior
90
+
91
+ ```rust
92
+ async fn select_example() {
93
+ select! {
94
+ _ = operation_a() => {
95
+ println!("A completed first");
96
+ // operation_b() is dropped/cancelled
97
+ }
98
+ _ = operation_b() => {
99
+ println!("B completed first");
100
+ // operation_a() is dropped/cancelled
101
+ }
102
+ }
103
+ }
104
+
105
+ // Futures are cancelled at their next .await point
106
+ // For immediate cancellation, futures must be cancel-safe
107
+ ```
108
+
109
+ ## Biased Selection
110
+
111
+ ```rust
112
+ // By default, select! randomly picks when multiple are ready
113
+ // Use biased mode for deterministic priority
114
+ select! {
115
+ biased; // Check branches in order
116
+
117
+ msg = high_priority.recv() => handle_high(msg),
118
+ msg = low_priority.recv() => handle_low(msg),
119
+ }
120
+
121
+ // Without biased, both channels have equal chance
122
+ // when both have messages ready
123
+ ```
124
+
125
+ ## Loop with select!
126
+
127
+ ```rust
128
+ async fn event_loop(
129
+ mut commands: mpsc::Receiver<Command>,
130
+ shutdown: CancellationToken,
131
+ ) {
132
+ loop {
133
+ select! {
134
+ _ = shutdown.cancelled() => {
135
+ println!("Shutting down");
136
+ break;
137
+ }
138
+ Some(cmd) = commands.recv() => {
139
+ process_command(cmd).await;
140
+ }
141
+ else => {
142
+ // commands channel closed
143
+ break;
144
+ }
145
+ }
146
+ }
147
+ }
148
+ ```
149
+
150
+ ## Racing Multiple of Same Type
151
+
152
+ ```rust
153
+ // Race multiple servers for fastest response
154
+ async fn fastest_response(servers: &[String]) -> Result<Response> {
155
+ let futures = servers.iter()
156
+ .map(|s| fetch_from(s))
157
+ .collect::<Vec<_>>();
158
+
159
+ // select! requires static branches, use select_all for dynamic
160
+ let (result, _index, _remaining) =
161
+ futures::future::select_all(futures).await;
162
+
163
+ result
164
+ }
165
+ ```
166
+
167
+ ## Common Patterns
168
+
169
+ ```rust
170
+ // Timeout
171
+ select! {
172
+ result = operation() => result,
173
+ _ = sleep(Duration::from_secs(5)) => Err(Timeout),
174
+ }
175
+
176
+ // Cancellation
177
+ select! {
178
+ result = operation() => result,
179
+ _ = cancel_token.cancelled() => Err(Cancelled),
180
+ }
181
+
182
+ // Interval with cancellation
183
+ let mut interval = tokio::time::interval(Duration::from_secs(1));
184
+ loop {
185
+ select! {
186
+ _ = shutdown.cancelled() => break,
187
+ _ = interval.tick() => {
188
+ do_periodic_work().await;
189
+ }
190
+ }
191
+ }
192
+ ```
193
+
194
+ ## See Also
195
+
196
+ - [async-cancellation-token](./async-cancellation-token.md) - Cancellation patterns
197
+ - [async-join-parallel](./async-join-parallel.md) - All futures, not racing
198
+ - [async-bounded-channel](./async-bounded-channel.md) - Channel operations in select
@@ -0,0 +1,154 @@
1
+ # async-spawn-blocking
2
+
3
+ > Use `spawn_blocking` for CPU-intensive work
4
+
5
+ ## Why It Matters
6
+
7
+ Async runtimes like Tokio use a small number of threads to handle many tasks. CPU-intensive or blocking operations on these threads starve other tasks. `spawn_blocking` moves such work to a dedicated thread pool.
8
+
9
+ ## Bad
10
+
11
+ ```rust
12
+ // BAD: Blocks the async runtime thread
13
+ async fn process_image(data: &[u8]) -> ProcessedImage {
14
+ // CPU-intensive work on async thread!
15
+ let resized = resize_image(data); // Blocks!
16
+ let compressed = compress(resized); // Blocks!
17
+ compressed
18
+ }
19
+
20
+ // BAD: Synchronous file I/O in async context
21
+ async fn read_large_file(path: &Path) -> Vec<u8> {
22
+ std::fs::read(path).unwrap() // Blocks the runtime!
23
+ }
24
+ ```
25
+
26
+ ## Good
27
+
28
+ ```rust
29
+ use tokio::task;
30
+
31
+ // GOOD: Offload CPU work to blocking pool
32
+ async fn process_image(data: Vec<u8>) -> ProcessedImage {
33
+ task::spawn_blocking(move || {
34
+ let resized = resize_image(&data);
35
+ compress(resized)
36
+ })
37
+ .await
38
+ .expect("spawn_blocking failed")
39
+ }
40
+
41
+ // GOOD: Use async file I/O
42
+ async fn read_large_file(path: &Path) -> tokio::io::Result<Vec<u8>> {
43
+ tokio::fs::read(path).await
44
+ }
45
+
46
+ // GOOD: Or spawn_blocking for unavoidable sync I/O
47
+ async fn read_with_sync_lib(path: PathBuf) -> Vec<u8> {
48
+ task::spawn_blocking(move || {
49
+ sync_library::read_file(&path)
50
+ })
51
+ .await
52
+ .unwrap()
53
+ }
54
+ ```
55
+
56
+ ## What Counts as Blocking
57
+
58
+ ```rust
59
+ // CPU-intensive operations
60
+ - Cryptographic operations (hashing, encryption)
61
+ - Image/video processing
62
+ - Compression/decompression
63
+ - Complex parsing
64
+ - Mathematical computations
65
+
66
+ // Blocking I/O
67
+ - std::fs operations
68
+ - Synchronous database drivers
69
+ - Synchronous HTTP clients
70
+ - Thread::sleep
71
+
72
+ // Example thresholds (rough guidelines):
73
+ // < 10µs: OK on async thread
74
+ // 10µs - 1ms: Consider spawn_blocking
75
+ // > 1ms: Definitely spawn_blocking
76
+ ```
77
+
78
+ ## Practical Examples
79
+
80
+ ```rust
81
+ // Password hashing (CPU-intensive)
82
+ async fn hash_password(password: String) -> String {
83
+ task::spawn_blocking(move || {
84
+ bcrypt::hash(password, bcrypt::DEFAULT_COST).unwrap()
85
+ })
86
+ .await
87
+ .unwrap()
88
+ }
89
+
90
+ // JSON parsing of large documents
91
+ async fn parse_large_json(data: String) -> serde_json::Value {
92
+ task::spawn_blocking(move || {
93
+ serde_json::from_str(&data).unwrap()
94
+ })
95
+ .await
96
+ .unwrap()
97
+ }
98
+
99
+ // Compression
100
+ async fn compress_data(data: Vec<u8>) -> Vec<u8> {
101
+ task::spawn_blocking(move || {
102
+ let mut encoder = flate2::write::GzEncoder::new(
103
+ Vec::new(),
104
+ flate2::Compression::default(),
105
+ );
106
+ encoder.write_all(&data).unwrap();
107
+ encoder.finish().unwrap()
108
+ })
109
+ .await
110
+ .unwrap()
111
+ }
112
+ ```
113
+
114
+ ## spawn_blocking vs spawn
115
+
116
+ ```rust
117
+ // spawn: Runs async code on runtime threads
118
+ tokio::spawn(async {
119
+ // Async code here
120
+ some_async_operation().await;
121
+ });
122
+
123
+ // spawn_blocking: Runs sync code on blocking thread pool
124
+ tokio::task::spawn_blocking(|| {
125
+ // Synchronous, possibly CPU-intensive code
126
+ heavy_computation();
127
+ });
128
+
129
+ // spawn_blocking returns JoinHandle that can be awaited
130
+ let result = tokio::task::spawn_blocking(|| {
131
+ expensive_sync_operation()
132
+ }).await?;
133
+ ```
134
+
135
+ ## Rayon for Parallel CPU Work
136
+
137
+ ```rust
138
+ // For parallel CPU work, consider Rayon inside spawn_blocking
139
+ async fn parallel_process(items: Vec<Item>) -> Vec<Output> {
140
+ task::spawn_blocking(move || {
141
+ use rayon::prelude::*;
142
+ items.par_iter()
143
+ .map(|item| cpu_intensive_transform(item))
144
+ .collect()
145
+ })
146
+ .await
147
+ .unwrap()
148
+ }
149
+ ```
150
+
151
+ ## See Also
152
+
153
+ - [async-tokio-fs](async-tokio-fs.md) - Use tokio::fs for async file I/O
154
+ - [async-no-lock-await](async-no-lock-await.md) - Don't hold locks across await