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,167 @@
1
+ # async-tokio-fs
2
+
3
+ > Use `tokio::fs` instead of `std::fs` in async code
4
+
5
+ ## Why It Matters
6
+
7
+ `std::fs` operations are blocking—they stop the current thread until the syscall completes. In async code, this blocks the executor thread, preventing it from running other tasks. `tokio::fs` wraps filesystem operations in `spawn_blocking`, keeping the executor responsive.
8
+
9
+ ## Bad
10
+
11
+ ```rust
12
+ async fn process_files(paths: &[PathBuf]) -> Result<Vec<String>> {
13
+ let mut contents = Vec::new();
14
+
15
+ for path in paths {
16
+ // BLOCKS the entire executor thread!
17
+ let data = std::fs::read_to_string(path)?;
18
+ contents.push(data);
19
+ }
20
+
21
+ Ok(contents)
22
+ }
23
+
24
+ // While reading a file, NO other tasks can run on this thread
25
+ ```
26
+
27
+ ## Good
28
+
29
+ ```rust
30
+ use tokio::fs;
31
+
32
+ async fn process_files(paths: &[PathBuf]) -> Result<Vec<String>> {
33
+ let mut contents = Vec::new();
34
+
35
+ for path in paths {
36
+ // Non-blocking: allows other tasks to run
37
+ let data = fs::read_to_string(path).await?;
38
+ contents.push(data);
39
+ }
40
+
41
+ Ok(contents)
42
+ }
43
+
44
+ // Even better: concurrent reads
45
+ async fn process_files_concurrent(paths: &[PathBuf]) -> Result<Vec<String>> {
46
+ let futures: Vec<_> = paths.iter()
47
+ .map(|path| fs::read_to_string(path))
48
+ .collect();
49
+
50
+ futures::future::try_join_all(futures).await
51
+ }
52
+ ```
53
+
54
+ ## tokio::fs API
55
+
56
+ ```rust
57
+ use tokio::fs;
58
+
59
+ // Reading
60
+ let contents = fs::read_to_string("file.txt").await?;
61
+ let bytes = fs::read("file.bin").await?;
62
+
63
+ // Writing
64
+ fs::write("output.txt", "contents").await?;
65
+
66
+ // File operations
67
+ let file = fs::File::open("file.txt").await?;
68
+ let file = fs::File::create("new.txt").await?;
69
+
70
+ // Directory operations
71
+ fs::create_dir("new_dir").await?;
72
+ fs::create_dir_all("nested/dir/path").await?;
73
+ fs::remove_dir("empty_dir").await?;
74
+ fs::remove_dir_all("dir_with_contents").await?;
75
+
76
+ // Metadata
77
+ let metadata = fs::metadata("file.txt").await?;
78
+ let canonical = fs::canonicalize("./relative").await?;
79
+
80
+ // Rename/remove
81
+ fs::rename("old.txt", "new.txt").await?;
82
+ fs::remove_file("file.txt").await?;
83
+
84
+ // Read directory
85
+ let mut entries = fs::read_dir("some_dir").await?;
86
+ while let Some(entry) = entries.next_entry().await? {
87
+ println!("{}", entry.path().display());
88
+ }
89
+ ```
90
+
91
+ ## Async File I/O
92
+
93
+ ```rust
94
+ use tokio::fs::File;
95
+ use tokio::io::{AsyncReadExt, AsyncWriteExt, AsyncBufReadExt, BufReader};
96
+
97
+ // Read with buffer
98
+ let mut file = File::open("large.bin").await?;
99
+ let mut buffer = vec![0u8; 4096];
100
+ let bytes_read = file.read(&mut buffer).await?;
101
+
102
+ // Read all
103
+ let mut contents = Vec::new();
104
+ file.read_to_end(&mut contents).await?;
105
+
106
+ // Write
107
+ let mut file = File::create("output.bin").await?;
108
+ file.write_all(b"data").await?;
109
+ file.flush().await?;
110
+
111
+ // Buffered line reading
112
+ let file = File::open("lines.txt").await?;
113
+ let reader = BufReader::new(file);
114
+ let mut lines = reader.lines();
115
+
116
+ while let Some(line) = lines.next_line().await? {
117
+ println!("{}", line);
118
+ }
119
+ ```
120
+
121
+ ## When std::fs is Acceptable
122
+
123
+ ```rust
124
+ // Startup/initialization (before async runtime)
125
+ fn main() {
126
+ let config = std::fs::read_to_string("config.toml")
127
+ .expect("config file required");
128
+
129
+ tokio::runtime::Runtime::new()
130
+ .unwrap()
131
+ .block_on(run_with_config(config));
132
+ }
133
+
134
+ // Single-threaded current_thread runtime (less impact)
135
+ #[tokio::main(flavor = "current_thread")]
136
+ async fn main() {
137
+ // Still prefer tokio::fs, but impact is lower
138
+ }
139
+
140
+ // When file operations are rare and quick
141
+ // (e.g., reading small config once per hour)
142
+ ```
143
+
144
+ ## Performance Considerations
145
+
146
+ ```rust
147
+ // tokio::fs uses spawn_blocking internally
148
+ // For many small files, the overhead adds up
149
+
150
+ // Batch operations when possible
151
+ let paths: Vec<_> = entries.iter()
152
+ .map(|e| e.path())
153
+ .collect();
154
+
155
+ let contents = futures::future::try_join_all(
156
+ paths.iter().map(|p| fs::read_to_string(p))
157
+ ).await?;
158
+
159
+ // For heavy I/O, consider memory-mapped files
160
+ // (requires unsafe or mmap crate)
161
+ ```
162
+
163
+ ## See Also
164
+
165
+ - [async-spawn-blocking](./async-spawn-blocking.md) - How tokio::fs works internally
166
+ - [async-tokio-runtime](./async-tokio-runtime.md) - Runtime configuration
167
+ - [err-context-chain](./err-context-chain.md) - Adding path context to IO errors
@@ -0,0 +1,169 @@
1
+ # async-tokio-runtime
2
+
3
+ > Configure Tokio runtime appropriately for your workload
4
+
5
+ ## Why It Matters
6
+
7
+ Tokio's default multi-threaded runtime isn't always optimal. CPU-bound work needs different configuration than IO-bound work. Incorrect configuration leads to poor performance, blocked workers, or resource exhaustion. Understanding runtime options lets you tune for your specific use case.
8
+
9
+ ## Bad
10
+
11
+ ```rust
12
+ // Default runtime for everything - not optimal
13
+ #[tokio::main]
14
+ async fn main() {
15
+ // CPU-heavy work on async executor starves IO tasks
16
+ for data in datasets {
17
+ let result = heavy_computation(data).await;
18
+ }
19
+ }
20
+
21
+ // Single-threaded when multi-threaded is needed
22
+ #[tokio::main(flavor = "current_thread")]
23
+ async fn main() {
24
+ // Can't utilize multiple cores for concurrent tasks
25
+ for _ in 0..1000 {
26
+ tokio::spawn(async { /* IO work */ });
27
+ }
28
+ }
29
+ ```
30
+
31
+ ## Good
32
+
33
+ ```rust
34
+ // Multi-threaded for concurrent IO (default)
35
+ #[tokio::main]
36
+ async fn main() {
37
+ // Good for many concurrent network connections
38
+ let handles: Vec<_> = urls.iter()
39
+ .map(|url| tokio::spawn(fetch(url.clone())))
40
+ .collect();
41
+
42
+ futures::future::join_all(handles).await;
43
+ }
44
+
45
+ // Current-thread for single-threaded scenarios
46
+ #[tokio::main(flavor = "current_thread")]
47
+ async fn main() {
48
+ // Good for single-connection clients, simpler debugging
49
+ let client = Client::new();
50
+ client.run().await;
51
+ }
52
+
53
+ // Custom configuration
54
+ #[tokio::main(worker_threads = 4)]
55
+ async fn main() {
56
+ // Limit to 4 worker threads
57
+ }
58
+
59
+ // Or manual setup for more control
60
+ fn main() {
61
+ let runtime = tokio::runtime::Builder::new_multi_thread()
62
+ .worker_threads(4)
63
+ .enable_all()
64
+ .thread_name("my-worker")
65
+ .build()
66
+ .unwrap();
67
+
68
+ runtime.block_on(async_main());
69
+ }
70
+ ```
71
+
72
+ ## Runtime Types
73
+
74
+ | Runtime | Use Case | Configuration |
75
+ |---------|----------|---------------|
76
+ | Multi-thread | IO-bound, many connections | `#[tokio::main]` (default) |
77
+ | Current-thread | CLI tools, tests, single connection | `flavor = "current_thread"` |
78
+ | Custom | Fine-tuned performance | `Builder::new_*()` |
79
+
80
+ ## Worker Thread Tuning
81
+
82
+ ```rust
83
+ use tokio::runtime::Builder;
84
+
85
+ // IO-bound: more threads than cores can help
86
+ let io_runtime = Builder::new_multi_thread()
87
+ .worker_threads(num_cpus::get() * 2) // IO can benefit from oversubscription
88
+ .max_blocking_threads(32) // For spawn_blocking calls
89
+ .enable_io()
90
+ .enable_time()
91
+ .build()?;
92
+
93
+ // CPU-bound: match core count
94
+ let cpu_runtime = Builder::new_multi_thread()
95
+ .worker_threads(num_cpus::get()) // No benefit from more than cores
96
+ .build()?;
97
+ ```
98
+
99
+ ## Multiple Runtimes
100
+
101
+ ```rust
102
+ // Separate runtimes for different workloads
103
+ struct App {
104
+ io_runtime: Runtime,
105
+ cpu_runtime: Runtime,
106
+ }
107
+
108
+ impl App {
109
+ fn new() -> Self {
110
+ Self {
111
+ io_runtime: Builder::new_multi_thread()
112
+ .worker_threads(8)
113
+ .thread_name("io-worker")
114
+ .build()
115
+ .unwrap(),
116
+ cpu_runtime: Builder::new_multi_thread()
117
+ .worker_threads(4)
118
+ .thread_name("cpu-worker")
119
+ .build()
120
+ .unwrap(),
121
+ }
122
+ }
123
+
124
+ fn spawn_io<F>(&self, future: F)
125
+ where F: Future + Send + 'static, F::Output: Send + 'static
126
+ {
127
+ self.io_runtime.spawn(future);
128
+ }
129
+
130
+ fn spawn_cpu<F>(&self, task: F)
131
+ where F: FnOnce() + Send + 'static
132
+ {
133
+ self.cpu_runtime.spawn_blocking(task);
134
+ }
135
+ }
136
+ ```
137
+
138
+ ## Runtime in Tests
139
+
140
+ ```rust
141
+ // Single test runtime
142
+ #[tokio::test]
143
+ async fn test_single() {
144
+ assert!(true);
145
+ }
146
+
147
+ // Multi-threaded test
148
+ #[tokio::test(flavor = "multi_thread", worker_threads = 2)]
149
+ async fn test_concurrent() {
150
+ let (tx, rx) = tokio::sync::oneshot::channel();
151
+ tokio::spawn(async move { tx.send(42).unwrap() });
152
+ assert_eq!(rx.await.unwrap(), 42);
153
+ }
154
+
155
+ // Custom runtime in test
156
+ #[test]
157
+ fn test_with_custom_runtime() {
158
+ let rt = Builder::new_current_thread().build().unwrap();
159
+ rt.block_on(async {
160
+ // test code
161
+ });
162
+ }
163
+ ```
164
+
165
+ ## See Also
166
+
167
+ - [async-spawn-blocking](./async-spawn-blocking.md) - Handling blocking code
168
+ - [async-no-lock-await](./async-no-lock-await.md) - Avoiding lock issues
169
+ - [async-joinset-structured](./async-joinset-structured.md) - Managing spawned tasks
@@ -0,0 +1,172 @@
1
+ # async-try-join
2
+
3
+ > Use `try_join!` for concurrent fallible operations with early return on error
4
+
5
+ ## Why It Matters
6
+
7
+ When running multiple fallible operations concurrently, `try_join!` returns `Err` as soon as any future fails, without waiting for the others. This provides fail-fast behavior while still running operations in parallel. For many operations, use `futures::future::try_join_all`.
8
+
9
+ ## Bad
10
+
11
+ ```rust
12
+ // Sequential - slow and no early return benefit
13
+ async fn fetch_all() -> Result<(A, B, C)> {
14
+ let a = fetch_a().await?; // If this fails, we wait for nothing
15
+ let b = fetch_b().await?; // But if this fails, we waited for A
16
+ let c = fetch_c().await?;
17
+ Ok((a, b, c))
18
+ }
19
+
20
+ // join! ignores errors
21
+ async fn fetch_all() -> (Result<A>, Result<B>, Result<C>) {
22
+ let (a, b, c) = join!(fetch_a(), fetch_b(), fetch_c());
23
+ // All complete even if first one failed
24
+ (a, b, c) // Now we have to handle three Results
25
+ }
26
+ ```
27
+
28
+ ## Good
29
+
30
+ ```rust
31
+ use tokio::try_join;
32
+
33
+ async fn fetch_all() -> Result<(A, B, C)> {
34
+ // Concurrent AND fail-fast
35
+ let (a, b, c) = try_join!(
36
+ fetch_a(),
37
+ fetch_b(),
38
+ fetch_c(),
39
+ )?;
40
+
41
+ Ok((a, b, c))
42
+ }
43
+
44
+ // For dynamic collections
45
+ use futures::future::try_join_all;
46
+
47
+ async fn fetch_users(ids: &[u64]) -> Result<Vec<User>> {
48
+ let futures: Vec<_> = ids.iter()
49
+ .map(|id| fetch_user(*id))
50
+ .collect();
51
+
52
+ try_join_all(futures).await
53
+ }
54
+ ```
55
+
56
+ ## Error Handling Patterns
57
+
58
+ ```rust
59
+ // Different error types - need common error type
60
+ async fn mixed_operations() -> Result<(A, B), Error> {
61
+ let (a, b) = try_join!(
62
+ fetch_a().map_err(Error::from), // Convert errors
63
+ fetch_b().map_err(Error::from),
64
+ )?;
65
+ Ok((a, b))
66
+ }
67
+
68
+ // Collect all results, then handle errors
69
+ async fn all_or_nothing(ids: &[u64]) -> Result<Vec<User>> {
70
+ try_join_all(ids.iter().map(|id| fetch_user(*id))).await
71
+ }
72
+
73
+ // Collect successes, log failures
74
+ async fn best_effort(ids: &[u64]) -> Vec<User> {
75
+ let results = futures::future::join_all(
76
+ ids.iter().map(|id| fetch_user(*id))
77
+ ).await;
78
+
79
+ results.into_iter()
80
+ .filter_map(|r| match r {
81
+ Ok(user) => Some(user),
82
+ Err(e) => {
83
+ log::warn!("Failed to fetch user: {}", e);
84
+ None
85
+ }
86
+ })
87
+ .collect()
88
+ }
89
+ ```
90
+
91
+ ## Cancellation Behavior
92
+
93
+ ```rust
94
+ // try_join! cancels remaining futures on error
95
+ async fn with_cancellation() -> Result<()> {
96
+ // If fetch_a() fails, fetch_b() and fetch_c() are dropped
97
+ // But "dropped" != "immediately stopped"
98
+ // They stop at their next .await point
99
+
100
+ try_join!(
101
+ async {
102
+ fetch_a().await?;
103
+ cleanup_a().await; // May not run if other future fails
104
+ Ok::<_, Error>(())
105
+ },
106
+ async {
107
+ fetch_b().await?;
108
+ cleanup_b().await; // May not run if other future fails
109
+ Ok::<_, Error>(())
110
+ },
111
+ )?;
112
+
113
+ Ok(())
114
+ }
115
+
116
+ // For guaranteed cleanup, use Drop guards or explicit handling
117
+ ```
118
+
119
+ ## With Timeout
120
+
121
+ ```rust
122
+ use tokio::time::{timeout, Duration};
123
+
124
+ async fn fetch_with_timeout() -> Result<(A, B)> {
125
+ timeout(
126
+ Duration::from_secs(10),
127
+ try_join!(fetch_a(), fetch_b())
128
+ )
129
+ .await
130
+ .map_err(|_| Error::Timeout)?
131
+ }
132
+
133
+ // Per-operation timeout
134
+ async fn individual_timeouts() -> Result<(A, B)> {
135
+ try_join!(
136
+ timeout(Duration::from_secs(5), fetch_a())
137
+ .map_err(|_| Error::Timeout)
138
+ .and_then(|r| async { r }),
139
+ timeout(Duration::from_secs(5), fetch_b())
140
+ .map_err(|_| Error::Timeout)
141
+ .and_then(|r| async { r }),
142
+ )
143
+ }
144
+ ```
145
+
146
+ ## try_join! vs FuturesUnordered
147
+
148
+ ```rust
149
+ use futures::stream::{FuturesUnordered, StreamExt};
150
+
151
+ // try_join!: wait for all, fail fast
152
+ let (a, b, c) = try_join!(fa, fb, fc)?;
153
+
154
+ // FuturesUnordered: process as they complete
155
+ let mut futures = FuturesUnordered::new();
156
+ futures.push(fetch_a());
157
+ futures.push(fetch_b());
158
+ futures.push(fetch_c());
159
+
160
+ while let Some(result) = futures.next().await {
161
+ match result {
162
+ Ok(data) => process(data),
163
+ Err(e) => return Err(e), // Can fail fast manually
164
+ }
165
+ }
166
+ ```
167
+
168
+ ## See Also
169
+
170
+ - [async-join-parallel](./async-join-parallel.md) - Non-fallible concurrent futures
171
+ - [async-select-racing](./async-select-racing.md) - First-to-complete semantics
172
+ - [err-question-mark](./err-question-mark.md) - Error propagation
@@ -0,0 +1,189 @@
1
+ # async-watch-latest
2
+
3
+ > Use `watch` channel for sharing the latest value with multiple observers
4
+
5
+ ## Why It Matters
6
+
7
+ `watch` is optimized for scenarios where receivers only care about the most recent value, not the history of changes. Unlike `broadcast`, slow receivers don't lag—they simply skip intermediate values. This is perfect for configuration, state, or status that should always reflect the current situation.
8
+
9
+ ## Bad
10
+
11
+ ```rust
12
+ // Using broadcast when only latest value matters
13
+ let (tx, _) = broadcast::channel::<Config>(100);
14
+
15
+ // Receivers might process stale configs if they're slow
16
+ // And they waste time processing intermediate values
17
+
18
+ // Using mpsc with buffered stale values
19
+ let (tx, mut rx) = mpsc::channel::<Status>(100);
20
+ // Receiver might process outdated statuses
21
+ ```
22
+
23
+ ## Good
24
+
25
+ ```rust
26
+ use tokio::sync::watch;
27
+
28
+ let (tx, rx) = watch::channel(Config::default());
29
+
30
+ // Multiple observers
31
+ let rx1 = rx.clone();
32
+ let rx2 = rx.clone();
33
+
34
+ // Observer 1: waits for changes
35
+ tokio::spawn(async move {
36
+ let mut rx = rx1;
37
+ while rx.changed().await.is_ok() {
38
+ let config = rx.borrow();
39
+ apply_config(&*config);
40
+ }
41
+ });
42
+
43
+ // Observer 2: also sees all changes
44
+ tokio::spawn(async move {
45
+ let mut rx = rx2;
46
+ while rx.changed().await.is_ok() {
47
+ let config = rx.borrow();
48
+ log_config_change(&*config);
49
+ }
50
+ });
51
+
52
+ // Update the value
53
+ tx.send(Config::new())?;
54
+ ```
55
+
56
+ ## watch Semantics
57
+
58
+ ```rust
59
+ use tokio::sync::watch;
60
+
61
+ let (tx, mut rx) = watch::channel("initial");
62
+
63
+ // Immediate read - no waiting
64
+ assert_eq!(*rx.borrow(), "initial");
65
+
66
+ // Wait for change
67
+ tx.send("updated")?;
68
+ rx.changed().await?;
69
+ assert_eq!(*rx.borrow(), "updated");
70
+
71
+ // Multiple rapid updates - receiver sees latest
72
+ tx.send("v1")?;
73
+ tx.send("v2")?;
74
+ tx.send("v3")?;
75
+ rx.changed().await?;
76
+ assert_eq!(*rx.borrow(), "v3"); // Skipped v1, v2
77
+ ```
78
+
79
+ ## Configuration Reload Pattern
80
+
81
+ ```rust
82
+ use tokio::sync::watch;
83
+ use std::sync::Arc;
84
+
85
+ struct AppConfig {
86
+ log_level: Level,
87
+ max_connections: usize,
88
+ }
89
+
90
+ async fn config_watcher(tx: watch::Sender<Arc<AppConfig>>) {
91
+ loop {
92
+ tokio::time::sleep(Duration::from_secs(60)).await;
93
+
94
+ if let Ok(new_config) = reload_config_from_disk() {
95
+ // Only notifies if value actually changed
96
+ tx.send_if_modified(|current| {
97
+ if *current != new_config {
98
+ *current = Arc::new(new_config);
99
+ true
100
+ } else {
101
+ false
102
+ }
103
+ });
104
+ }
105
+ }
106
+ }
107
+
108
+ async fn worker(mut config_rx: watch::Receiver<Arc<AppConfig>>) {
109
+ loop {
110
+ tokio::select! {
111
+ _ = config_rx.changed() => {
112
+ let config = config_rx.borrow().clone();
113
+ reconfigure(&config);
114
+ }
115
+ _ = do_work() => {}
116
+ }
117
+ }
118
+ }
119
+ ```
120
+
121
+ ## State Machine Updates
122
+
123
+ ```rust
124
+ #[derive(Clone, PartialEq)]
125
+ enum ConnectionState {
126
+ Disconnected,
127
+ Connecting,
128
+ Connected,
129
+ Error(String),
130
+ }
131
+
132
+ struct Connection {
133
+ state_tx: watch::Sender<ConnectionState>,
134
+ state_rx: watch::Receiver<ConnectionState>,
135
+ }
136
+
137
+ impl Connection {
138
+ async fn wait_connected(&mut self) -> Result<(), Error> {
139
+ loop {
140
+ let state = self.state_rx.borrow().clone();
141
+ match state {
142
+ ConnectionState::Connected => return Ok(()),
143
+ ConnectionState::Error(e) => return Err(Error::Connection(e)),
144
+ _ => {
145
+ self.state_rx.changed().await?;
146
+ }
147
+ }
148
+ }
149
+ }
150
+ }
151
+ ```
152
+
153
+ ## Borrow vs Clone
154
+
155
+ ```rust
156
+ use tokio::sync::watch;
157
+
158
+ let (tx, rx) = watch::channel(vec![1, 2, 3]);
159
+
160
+ // borrow() returns Ref - must not hold across await
161
+ {
162
+ let data = rx.borrow();
163
+ println!("{:?}", *data);
164
+ } // Ref dropped here
165
+
166
+ // For use across await, clone the data
167
+ let data = rx.borrow().clone();
168
+ some_async_operation().await;
169
+ use_data(&data); // Safe
170
+
171
+ // Or use borrow_and_update() to mark as seen
172
+ let data = rx.borrow_and_update().clone();
173
+ ```
174
+
175
+ ## watch vs broadcast vs mpsc
176
+
177
+ | Feature | watch | broadcast | mpsc |
178
+ |---------|-------|-----------|------|
179
+ | Receivers | Multiple | Multiple | Single |
180
+ | Message delivery | Latest only | All messages | All messages |
181
+ | Slow receiver | Skips to latest | Lags/misses | Backpressure |
182
+ | Clone required | No | Yes | No |
183
+ | Best for | Config, status | Events | Work queues |
184
+
185
+ ## See Also
186
+
187
+ - [async-broadcast-pubsub](./async-broadcast-pubsub.md) - When history matters
188
+ - [async-mpsc-queue](./async-mpsc-queue.md) - Work queue patterns
189
+ - [async-cancellation-token](./async-cancellation-token.md) - Related pattern