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.
- package/README.md +47 -150
- package/package.json +1 -1
- package/template/agent/patches/skills-patches.md +23 -0
- package/template/agent/rules/scratch-scripts.md +37 -0
- package/template/agent/rules/superpowers.md +6 -50
- package/template/agent/skills/brainstorming/SKILL.md +4 -3
- package/template/agent/skills/brainstorming/visual-companion.md +2 -3
- package/template/agent/skills/finishing-a-development-branch/SKILL.md +11 -16
- package/template/agent/skills/subagent-driven-development/SKILL.md +16 -0
- package/template/agent/skills/subagent-driven-development/implementer-prompt.md +4 -3
- package/template/agent/skills/using-git-worktrees/SKILL.md +3 -2
- package/template/agent/skills/using-superpowers/SKILL.md +8 -6
- package/template/agent/skills/using-superpowers/references/copilot-tools.md +52 -0
- package/template/agent/skills/writing-plans/SKILL.md +5 -3
- package/template/agent/skills/writing-skills/SKILL.md +1 -1
- package/template/agent/superpowers-version.json +2 -2
- package/template/agent/tmp/agent-config-backup.yml +9 -0
- package/template/agent/skills/ai-integrated-product/SKILL.md +0 -57
- package/template/agent/skills/analytics-setup/SKILL.md +0 -51
- package/template/agent/skills/api-design/SKILL.md +0 -193
- package/template/agent/skills/app-store-optimizer/SKILL.md +0 -127
- package/template/agent/skills/auth-and-identity/SKILL.md +0 -167
- package/template/agent/skills/backend-developer/SKILL.md +0 -148
- package/template/agent/skills/bootstrapper-finance/SKILL.md +0 -55
- package/template/agent/skills/chrome-extension-developer/SKILL.md +0 -53
- package/template/agent/skills/community-manager/SKILL.md +0 -115
- package/template/agent/skills/content-marketer/SKILL.md +0 -111
- package/template/agent/skills/conversion-optimizer/SKILL.md +0 -142
- package/template/agent/skills/cto-architect/SKILL.md +0 -133
- package/template/agent/skills/customer-success-manager/SKILL.md +0 -126
- package/template/agent/skills/data-analyst/SKILL.md +0 -147
- package/template/agent/skills/devops-engineer/SKILL.md +0 -117
- package/template/agent/skills/email-infrastructure/SKILL.md +0 -164
- package/template/agent/skills/game-design/SKILL.md +0 -194
- package/template/agent/skills/game-developer/SKILL.md +0 -175
- package/template/agent/skills/growth-hacker/SKILL.md +0 -122
- package/template/agent/skills/idea-validator/SKILL.md +0 -55
- package/template/agent/skills/indie-legal/SKILL.md +0 -53
- package/template/agent/skills/influencer-marketer/SKILL.md +0 -141
- package/template/agent/skills/landing-page-builder/SKILL.md +0 -59
- package/template/agent/skills/launch-strategist/SKILL.md +0 -62
- package/template/agent/skills/market-researcher/SKILL.md +0 -53
- package/template/agent/skills/micro-saas-builder/SKILL.md +0 -56
- package/template/agent/skills/monetization-strategist/SKILL.md +0 -119
- package/template/agent/skills/paid-acquisition-specialist/SKILL.md +0 -119
- package/template/agent/skills/pricing-psychologist/SKILL.md +0 -58
- package/template/agent/skills/real-time-features/SKILL.md +0 -194
- package/template/agent/skills/retention-specialist/SKILL.md +0 -123
- package/template/agent/skills/rust-developer/SKILL.md +0 -281
- package/template/agent/skills/rust-developer/references/rust-rules/_sections.md +0 -231
- package/template/agent/skills/rust-developer/references/rust-rules/anti-clone-excessive.md +0 -124
- package/template/agent/skills/rust-developer/references/rust-rules/anti-collect-intermediate.md +0 -131
- package/template/agent/skills/rust-developer/references/rust-rules/anti-empty-catch.md +0 -132
- package/template/agent/skills/rust-developer/references/rust-rules/anti-expect-lazy.md +0 -95
- package/template/agent/skills/rust-developer/references/rust-rules/anti-format-hot-path.md +0 -141
- package/template/agent/skills/rust-developer/references/rust-rules/anti-index-over-iter.md +0 -125
- package/template/agent/skills/rust-developer/references/rust-rules/anti-lock-across-await.md +0 -127
- package/template/agent/skills/rust-developer/references/rust-rules/anti-over-abstraction.md +0 -120
- package/template/agent/skills/rust-developer/references/rust-rules/anti-panic-expected.md +0 -131
- package/template/agent/skills/rust-developer/references/rust-rules/anti-premature-optimize.md +0 -156
- package/template/agent/skills/rust-developer/references/rust-rules/anti-string-for-str.md +0 -122
- package/template/agent/skills/rust-developer/references/rust-rules/anti-stringly-typed.md +0 -167
- package/template/agent/skills/rust-developer/references/rust-rules/anti-type-erasure.md +0 -134
- package/template/agent/skills/rust-developer/references/rust-rules/anti-unwrap-abuse.md +0 -143
- package/template/agent/skills/rust-developer/references/rust-rules/anti-vec-for-slice.md +0 -121
- package/template/agent/skills/rust-developer/references/rust-rules/api-builder-must-use.md +0 -143
- package/template/agent/skills/rust-developer/references/rust-rules/api-builder-pattern.md +0 -187
- package/template/agent/skills/rust-developer/references/rust-rules/api-common-traits.md +0 -165
- package/template/agent/skills/rust-developer/references/rust-rules/api-default-impl.md +0 -177
- package/template/agent/skills/rust-developer/references/rust-rules/api-extension-trait.md +0 -163
- package/template/agent/skills/rust-developer/references/rust-rules/api-from-not-into.md +0 -146
- package/template/agent/skills/rust-developer/references/rust-rules/api-impl-asref.md +0 -142
- package/template/agent/skills/rust-developer/references/rust-rules/api-impl-into.md +0 -160
- package/template/agent/skills/rust-developer/references/rust-rules/api-must-use.md +0 -125
- package/template/agent/skills/rust-developer/references/rust-rules/api-newtype-safety.md +0 -162
- package/template/agent/skills/rust-developer/references/rust-rules/api-non-exhaustive.md +0 -177
- package/template/agent/skills/rust-developer/references/rust-rules/api-parse-dont-validate.md +0 -184
- package/template/agent/skills/rust-developer/references/rust-rules/api-sealed-trait.md +0 -168
- package/template/agent/skills/rust-developer/references/rust-rules/api-serde-optional.md +0 -182
- package/template/agent/skills/rust-developer/references/rust-rules/api-typestate.md +0 -199
- package/template/agent/skills/rust-developer/references/rust-rules/async-bounded-channel.md +0 -175
- package/template/agent/skills/rust-developer/references/rust-rules/async-broadcast-pubsub.md +0 -185
- package/template/agent/skills/rust-developer/references/rust-rules/async-cancellation-token.md +0 -203
- package/template/agent/skills/rust-developer/references/rust-rules/async-clone-before-await.md +0 -171
- package/template/agent/skills/rust-developer/references/rust-rules/async-join-parallel.md +0 -158
- package/template/agent/skills/rust-developer/references/rust-rules/async-joinset-structured.md +0 -195
- package/template/agent/skills/rust-developer/references/rust-rules/async-mpsc-queue.md +0 -171
- package/template/agent/skills/rust-developer/references/rust-rules/async-no-lock-await.md +0 -156
- package/template/agent/skills/rust-developer/references/rust-rules/async-oneshot-response.md +0 -191
- package/template/agent/skills/rust-developer/references/rust-rules/async-select-racing.md +0 -198
- package/template/agent/skills/rust-developer/references/rust-rules/async-spawn-blocking.md +0 -154
- package/template/agent/skills/rust-developer/references/rust-rules/async-tokio-fs.md +0 -167
- package/template/agent/skills/rust-developer/references/rust-rules/async-tokio-runtime.md +0 -169
- package/template/agent/skills/rust-developer/references/rust-rules/async-try-join.md +0 -172
- package/template/agent/skills/rust-developer/references/rust-rules/async-watch-latest.md +0 -189
- package/template/agent/skills/rust-developer/references/rust-rules/doc-all-public.md +0 -113
- package/template/agent/skills/rust-developer/references/rust-rules/doc-cargo-metadata.md +0 -147
- package/template/agent/skills/rust-developer/references/rust-rules/doc-errors-section.md +0 -122
- package/template/agent/skills/rust-developer/references/rust-rules/doc-examples-section.md +0 -161
- package/template/agent/skills/rust-developer/references/rust-rules/doc-hidden-setup.md +0 -149
- package/template/agent/skills/rust-developer/references/rust-rules/doc-intra-links.md +0 -138
- package/template/agent/skills/rust-developer/references/rust-rules/doc-link-types.md +0 -169
- package/template/agent/skills/rust-developer/references/rust-rules/doc-module-inner.md +0 -116
- package/template/agent/skills/rust-developer/references/rust-rules/doc-panics-section.md +0 -128
- package/template/agent/skills/rust-developer/references/rust-rules/doc-question-mark.md +0 -136
- package/template/agent/skills/rust-developer/references/rust-rules/doc-safety-section.md +0 -131
- package/template/agent/skills/rust-developer/references/rust-rules/err-anyhow-app.md +0 -179
- package/template/agent/skills/rust-developer/references/rust-rules/err-context-chain.md +0 -144
- package/template/agent/skills/rust-developer/references/rust-rules/err-custom-type.md +0 -152
- package/template/agent/skills/rust-developer/references/rust-rules/err-doc-errors.md +0 -145
- package/template/agent/skills/rust-developer/references/rust-rules/err-expect-bugs-only.md +0 -133
- package/template/agent/skills/rust-developer/references/rust-rules/err-from-impl.md +0 -152
- package/template/agent/skills/rust-developer/references/rust-rules/err-lowercase-msg.md +0 -124
- package/template/agent/skills/rust-developer/references/rust-rules/err-no-unwrap-prod.md +0 -115
- package/template/agent/skills/rust-developer/references/rust-rules/err-question-mark.md +0 -151
- package/template/agent/skills/rust-developer/references/rust-rules/err-result-over-panic.md +0 -130
- package/template/agent/skills/rust-developer/references/rust-rules/err-source-chain.md +0 -155
- package/template/agent/skills/rust-developer/references/rust-rules/err-thiserror-lib.md +0 -171
- package/template/agent/skills/rust-developer/references/rust-rules/lint-cargo-metadata.md +0 -138
- package/template/agent/skills/rust-developer/references/rust-rules/lint-deny-correctness.md +0 -107
- package/template/agent/skills/rust-developer/references/rust-rules/lint-missing-docs.md +0 -154
- package/template/agent/skills/rust-developer/references/rust-rules/lint-pedantic-selective.md +0 -118
- package/template/agent/skills/rust-developer/references/rust-rules/lint-rustfmt-check.md +0 -157
- package/template/agent/skills/rust-developer/references/rust-rules/lint-unsafe-doc.md +0 -133
- package/template/agent/skills/rust-developer/references/rust-rules/lint-warn-complexity.md +0 -131
- package/template/agent/skills/rust-developer/references/rust-rules/lint-warn-perf.md +0 -136
- package/template/agent/skills/rust-developer/references/rust-rules/lint-warn-style.md +0 -135
- package/template/agent/skills/rust-developer/references/rust-rules/lint-warn-suspicious.md +0 -122
- package/template/agent/skills/rust-developer/references/rust-rules/lint-workspace-lints.md +0 -172
- package/template/agent/skills/rust-developer/references/rust-rules/mem-arena-allocator.md +0 -168
- package/template/agent/skills/rust-developer/references/rust-rules/mem-arrayvec.md +0 -142
- package/template/agent/skills/rust-developer/references/rust-rules/mem-assert-type-size.md +0 -168
- package/template/agent/skills/rust-developer/references/rust-rules/mem-avoid-format.md +0 -147
- package/template/agent/skills/rust-developer/references/rust-rules/mem-box-large-variant.md +0 -158
- package/template/agent/skills/rust-developer/references/rust-rules/mem-boxed-slice.md +0 -139
- package/template/agent/skills/rust-developer/references/rust-rules/mem-clone-from.md +0 -147
- package/template/agent/skills/rust-developer/references/rust-rules/mem-compact-string.md +0 -149
- package/template/agent/skills/rust-developer/references/rust-rules/mem-reuse-collections.md +0 -174
- package/template/agent/skills/rust-developer/references/rust-rules/mem-smaller-integers.md +0 -159
- package/template/agent/skills/rust-developer/references/rust-rules/mem-smallvec.md +0 -138
- package/template/agent/skills/rust-developer/references/rust-rules/mem-thinvec.md +0 -142
- package/template/agent/skills/rust-developer/references/rust-rules/mem-with-capacity.md +0 -156
- package/template/agent/skills/rust-developer/references/rust-rules/mem-write-over-format.md +0 -172
- package/template/agent/skills/rust-developer/references/rust-rules/mem-zero-copy.md +0 -164
- package/template/agent/skills/rust-developer/references/rust-rules/name-acronym-word.md +0 -99
- package/template/agent/skills/rust-developer/references/rust-rules/name-as-free.md +0 -104
- package/template/agent/skills/rust-developer/references/rust-rules/name-consts-screaming.md +0 -94
- package/template/agent/skills/rust-developer/references/rust-rules/name-crate-no-rs.md +0 -78
- package/template/agent/skills/rust-developer/references/rust-rules/name-funcs-snake.md +0 -76
- package/template/agent/skills/rust-developer/references/rust-rules/name-into-ownership.md +0 -123
- package/template/agent/skills/rust-developer/references/rust-rules/name-is-has-bool.md +0 -127
- package/template/agent/skills/rust-developer/references/rust-rules/name-iter-convention.md +0 -129
- package/template/agent/skills/rust-developer/references/rust-rules/name-iter-method.md +0 -131
- package/template/agent/skills/rust-developer/references/rust-rules/name-iter-type-match.md +0 -142
- package/template/agent/skills/rust-developer/references/rust-rules/name-lifetime-short.md +0 -86
- package/template/agent/skills/rust-developer/references/rust-rules/name-no-get-prefix.md +0 -154
- package/template/agent/skills/rust-developer/references/rust-rules/name-to-expensive.md +0 -118
- package/template/agent/skills/rust-developer/references/rust-rules/name-type-param-single.md +0 -92
- package/template/agent/skills/rust-developer/references/rust-rules/name-types-camel.md +0 -65
- package/template/agent/skills/rust-developer/references/rust-rules/name-variants-camel.md +0 -101
- package/template/agent/skills/rust-developer/references/rust-rules/opt-bounds-check.md +0 -161
- package/template/agent/skills/rust-developer/references/rust-rules/opt-cache-friendly.md +0 -187
- package/template/agent/skills/rust-developer/references/rust-rules/opt-codegen-units.md +0 -142
- package/template/agent/skills/rust-developer/references/rust-rules/opt-cold-unlikely.md +0 -152
- package/template/agent/skills/rust-developer/references/rust-rules/opt-inline-always-rare.md +0 -141
- package/template/agent/skills/rust-developer/references/rust-rules/opt-inline-never-cold.md +0 -181
- package/template/agent/skills/rust-developer/references/rust-rules/opt-inline-small.md +0 -160
- package/template/agent/skills/rust-developer/references/rust-rules/opt-likely-hint.md +0 -171
- package/template/agent/skills/rust-developer/references/rust-rules/opt-lto-release.md +0 -130
- package/template/agent/skills/rust-developer/references/rust-rules/opt-pgo-profile.md +0 -167
- package/template/agent/skills/rust-developer/references/rust-rules/opt-simd-portable.md +0 -144
- package/template/agent/skills/rust-developer/references/rust-rules/opt-target-cpu.md +0 -154
- package/template/agent/skills/rust-developer/references/rust-rules/own-arc-shared.md +0 -141
- package/template/agent/skills/rust-developer/references/rust-rules/own-borrow-over-clone.md +0 -95
- package/template/agent/skills/rust-developer/references/rust-rules/own-clone-explicit.md +0 -135
- package/template/agent/skills/rust-developer/references/rust-rules/own-copy-small.md +0 -124
- package/template/agent/skills/rust-developer/references/rust-rules/own-cow-conditional.md +0 -135
- package/template/agent/skills/rust-developer/references/rust-rules/own-lifetime-elision.md +0 -134
- package/template/agent/skills/rust-developer/references/rust-rules/own-move-large.md +0 -134
- package/template/agent/skills/rust-developer/references/rust-rules/own-mutex-interior.md +0 -105
- package/template/agent/skills/rust-developer/references/rust-rules/own-rc-single-thread.md +0 -65
- package/template/agent/skills/rust-developer/references/rust-rules/own-refcell-interior.md +0 -97
- package/template/agent/skills/rust-developer/references/rust-rules/own-rwlock-readers.md +0 -122
- package/template/agent/skills/rust-developer/references/rust-rules/own-slice-over-vec.md +0 -119
- package/template/agent/skills/rust-developer/references/rust-rules/perf-black-box-bench.md +0 -153
- package/template/agent/skills/rust-developer/references/rust-rules/perf-chain-avoid.md +0 -136
- package/template/agent/skills/rust-developer/references/rust-rules/perf-collect-into.md +0 -133
- package/template/agent/skills/rust-developer/references/rust-rules/perf-collect-once.md +0 -120
- package/template/agent/skills/rust-developer/references/rust-rules/perf-drain-reuse.md +0 -137
- package/template/agent/skills/rust-developer/references/rust-rules/perf-entry-api.md +0 -134
- package/template/agent/skills/rust-developer/references/rust-rules/perf-extend-batch.md +0 -150
- package/template/agent/skills/rust-developer/references/rust-rules/perf-iter-lazy.md +0 -123
- package/template/agent/skills/rust-developer/references/rust-rules/perf-iter-over-index.md +0 -113
- package/template/agent/skills/rust-developer/references/rust-rules/perf-profile-first.md +0 -175
- package/template/agent/skills/rust-developer/references/rust-rules/perf-release-profile.md +0 -149
- package/template/agent/skills/rust-developer/references/rust-rules/proj-bin-dir.md +0 -142
- package/template/agent/skills/rust-developer/references/rust-rules/proj-flat-small.md +0 -133
- package/template/agent/skills/rust-developer/references/rust-rules/proj-lib-main-split.md +0 -148
- package/template/agent/skills/rust-developer/references/rust-rules/proj-mod-by-feature.md +0 -130
- package/template/agent/skills/rust-developer/references/rust-rules/proj-mod-rs-dir.md +0 -120
- package/template/agent/skills/rust-developer/references/rust-rules/proj-prelude-module.md +0 -155
- package/template/agent/skills/rust-developer/references/rust-rules/proj-pub-crate-internal.md +0 -139
- package/template/agent/skills/rust-developer/references/rust-rules/proj-pub-super-parent.md +0 -135
- package/template/agent/skills/rust-developer/references/rust-rules/proj-pub-use-reexport.md +0 -162
- package/template/agent/skills/rust-developer/references/rust-rules/proj-workspace-deps.md +0 -186
- package/template/agent/skills/rust-developer/references/rust-rules/proj-workspace-large.md +0 -162
- package/template/agent/skills/rust-developer/references/rust-rules/test-arrange-act-assert.md +0 -160
- package/template/agent/skills/rust-developer/references/rust-rules/test-cfg-test-module.md +0 -151
- package/template/agent/skills/rust-developer/references/rust-rules/test-criterion-bench.md +0 -171
- package/template/agent/skills/rust-developer/references/rust-rules/test-descriptive-names.md +0 -142
- package/template/agent/skills/rust-developer/references/rust-rules/test-doctest-examples.md +0 -168
- package/template/agent/skills/rust-developer/references/rust-rules/test-fixture-raii.md +0 -151
- package/template/agent/skills/rust-developer/references/rust-rules/test-integration-dir.md +0 -144
- package/template/agent/skills/rust-developer/references/rust-rules/test-mock-traits.md +0 -189
- package/template/agent/skills/rust-developer/references/rust-rules/test-mockall-mocking.md +0 -226
- package/template/agent/skills/rust-developer/references/rust-rules/test-proptest-properties.md +0 -161
- package/template/agent/skills/rust-developer/references/rust-rules/test-should-panic.md +0 -130
- package/template/agent/skills/rust-developer/references/rust-rules/test-tokio-async.md +0 -154
- package/template/agent/skills/rust-developer/references/rust-rules/test-use-super.md +0 -127
- package/template/agent/skills/rust-developer/references/rust-rules/type-enum-states.md +0 -154
- package/template/agent/skills/rust-developer/references/rust-rules/type-generic-bounds.md +0 -142
- package/template/agent/skills/rust-developer/references/rust-rules/type-never-diverge.md +0 -146
- package/template/agent/skills/rust-developer/references/rust-rules/type-newtype-ids.md +0 -160
- package/template/agent/skills/rust-developer/references/rust-rules/type-newtype-validated.md +0 -159
- package/template/agent/skills/rust-developer/references/rust-rules/type-no-stringly.md +0 -144
- package/template/agent/skills/rust-developer/references/rust-rules/type-option-nullable.md +0 -137
- package/template/agent/skills/rust-developer/references/rust-rules/type-phantom-marker.md +0 -188
- package/template/agent/skills/rust-developer/references/rust-rules/type-repr-transparent.md +0 -143
- package/template/agent/skills/rust-developer/references/rust-rules/type-result-fallible.md +0 -131
- package/template/agent/skills/saas-architect/SKILL.md +0 -139
- package/template/agent/skills/security-engineer/SKILL.md +0 -133
- package/template/agent/skills/seo-specialist/SKILL.md +0 -130
- package/template/agent/skills/solo-founder-ops/SKILL.md +0 -56
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
# test-tokio-async
|
|
2
|
-
|
|
3
|
-
> Use `#[tokio::test]` for async tests
|
|
4
|
-
|
|
5
|
-
## Why It Matters
|
|
6
|
-
|
|
7
|
-
Async functions can't be called directly—they need a runtime to drive them. `#[tokio::test]` provides a Tokio runtime for your test, handling setup automatically. This is simpler than manually creating a runtime and essential for testing async code.
|
|
8
|
-
|
|
9
|
-
## Bad
|
|
10
|
-
|
|
11
|
-
```rust
|
|
12
|
-
// Won't compile - async fn can't be called without runtime
|
|
13
|
-
#[test]
|
|
14
|
-
async fn test_async_function() { // Error!
|
|
15
|
-
let result = fetch_data().await;
|
|
16
|
-
assert!(result.is_ok());
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
// Manual runtime - verbose and error-prone
|
|
20
|
-
#[test]
|
|
21
|
-
fn test_async_function() {
|
|
22
|
-
let rt = tokio::runtime::Runtime::new().unwrap();
|
|
23
|
-
rt.block_on(async {
|
|
24
|
-
let result = fetch_data().await;
|
|
25
|
-
assert!(result.is_ok());
|
|
26
|
-
});
|
|
27
|
-
}
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
## Good
|
|
31
|
-
|
|
32
|
-
```rust
|
|
33
|
-
#[tokio::test]
|
|
34
|
-
async fn test_async_function() {
|
|
35
|
-
let result = fetch_data().await;
|
|
36
|
-
assert!(result.is_ok());
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
#[tokio::test]
|
|
40
|
-
async fn test_concurrent_operations() {
|
|
41
|
-
let (a, b) = tokio::join!(
|
|
42
|
-
fetch_user(1),
|
|
43
|
-
fetch_user(2),
|
|
44
|
-
);
|
|
45
|
-
assert!(a.is_ok());
|
|
46
|
-
assert!(b.is_ok());
|
|
47
|
-
}
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
## Runtime Configuration
|
|
51
|
-
|
|
52
|
-
```rust
|
|
53
|
-
// Multi-threaded runtime (default)
|
|
54
|
-
#[tokio::test]
|
|
55
|
-
async fn test_default_runtime() {
|
|
56
|
-
// Uses multi-thread runtime
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// Single-threaded (current_thread)
|
|
60
|
-
#[tokio::test(flavor = "current_thread")]
|
|
61
|
-
async fn test_single_threaded() {
|
|
62
|
-
// Simpler, deterministic
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// With specific thread count
|
|
66
|
-
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
|
67
|
-
async fn test_with_workers() {
|
|
68
|
-
// Exactly 2 worker threads
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// With time control
|
|
72
|
-
#[tokio::test(start_paused = true)]
|
|
73
|
-
async fn test_with_time_control() {
|
|
74
|
-
// Time starts paused for deterministic testing
|
|
75
|
-
tokio::time::advance(Duration::from_secs(60)).await;
|
|
76
|
-
}
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
## Testing Timeouts
|
|
80
|
-
|
|
81
|
-
```rust
|
|
82
|
-
use tokio::time::{timeout, Duration};
|
|
83
|
-
|
|
84
|
-
#[tokio::test]
|
|
85
|
-
async fn test_operation_completes_in_time() {
|
|
86
|
-
let result = timeout(
|
|
87
|
-
Duration::from_secs(5),
|
|
88
|
-
slow_operation()
|
|
89
|
-
).await;
|
|
90
|
-
|
|
91
|
-
assert!(result.is_ok(), "Operation timed out");
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
#[tokio::test]
|
|
95
|
-
async fn test_timeout_triggers() {
|
|
96
|
-
let result = timeout(
|
|
97
|
-
Duration::from_millis(100),
|
|
98
|
-
never_completes()
|
|
99
|
-
).await;
|
|
100
|
-
|
|
101
|
-
assert!(result.is_err(), "Expected timeout");
|
|
102
|
-
}
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
## Testing Channels
|
|
106
|
-
|
|
107
|
-
```rust
|
|
108
|
-
use tokio::sync::mpsc;
|
|
109
|
-
|
|
110
|
-
#[tokio::test]
|
|
111
|
-
async fn test_channel_communication() {
|
|
112
|
-
let (tx, mut rx) = mpsc::channel(10);
|
|
113
|
-
|
|
114
|
-
tokio::spawn(async move {
|
|
115
|
-
tx.send("hello").await.unwrap();
|
|
116
|
-
tx.send("world").await.unwrap();
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
assert_eq!(rx.recv().await, Some("hello"));
|
|
120
|
-
assert_eq!(rx.recv().await, Some("world"));
|
|
121
|
-
assert_eq!(rx.recv().await, None);
|
|
122
|
-
}
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
## Testing with Mocks
|
|
126
|
-
|
|
127
|
-
```rust
|
|
128
|
-
use mockall::*;
|
|
129
|
-
|
|
130
|
-
#[automock]
|
|
131
|
-
#[async_trait::async_trait]
|
|
132
|
-
trait Database {
|
|
133
|
-
async fn get_user(&self, id: u64) -> Option<User>;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
#[tokio::test]
|
|
137
|
-
async fn test_with_mock_database() {
|
|
138
|
-
let mut mock = MockDatabase::new();
|
|
139
|
-
mock.expect_get_user()
|
|
140
|
-
.with(eq(42))
|
|
141
|
-
.returning(|_| Some(User { id: 42, name: "Alice".into() }));
|
|
142
|
-
|
|
143
|
-
let service = UserService::new(mock);
|
|
144
|
-
let user = service.find_user(42).await;
|
|
145
|
-
|
|
146
|
-
assert_eq!(user.unwrap().name, "Alice");
|
|
147
|
-
}
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
## See Also
|
|
151
|
-
|
|
152
|
-
- [async-tokio-runtime](./async-tokio-runtime.md) - Runtime configuration
|
|
153
|
-
- [test-mock-traits](./test-mock-traits.md) - Mocking async traits
|
|
154
|
-
- [test-fixture-raii](./test-fixture-raii.md) - Async test cleanup
|
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
# test-use-super
|
|
2
|
-
|
|
3
|
-
> Use `use super::*;` in test modules to access parent module items
|
|
4
|
-
|
|
5
|
-
## Why It Matters
|
|
6
|
-
|
|
7
|
-
The test module is a child of the module being tested. `use super::*` imports all items from the parent module, including private ones. This gives tests access to both public API and internal implementation details for thorough testing.
|
|
8
|
-
|
|
9
|
-
## Bad
|
|
10
|
-
|
|
11
|
-
```rust
|
|
12
|
-
// Verbose imports
|
|
13
|
-
#[cfg(test)]
|
|
14
|
-
mod tests {
|
|
15
|
-
use crate::my_module::public_function;
|
|
16
|
-
use crate::my_module::MyStruct;
|
|
17
|
-
// Can't access private items this way!
|
|
18
|
-
|
|
19
|
-
#[test]
|
|
20
|
-
fn test_function() {
|
|
21
|
-
let result = public_function();
|
|
22
|
-
// ...
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
## Good
|
|
28
|
-
|
|
29
|
-
```rust
|
|
30
|
-
// src/my_module.rs
|
|
31
|
-
pub struct PublicStruct { ... }
|
|
32
|
-
struct PrivateStruct { ... } // Private
|
|
33
|
-
|
|
34
|
-
pub fn public_function() -> i32 { ... }
|
|
35
|
-
fn private_helper() -> i32 { ... } // Private
|
|
36
|
-
|
|
37
|
-
#[cfg(test)]
|
|
38
|
-
mod tests {
|
|
39
|
-
use super::*; // Imports everything from parent
|
|
40
|
-
|
|
41
|
-
#[test]
|
|
42
|
-
fn test_public_struct() {
|
|
43
|
-
let s = PublicStruct::new();
|
|
44
|
-
// ...
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
#[test]
|
|
48
|
-
fn test_private_struct() {
|
|
49
|
-
let s = PrivateStruct::new(); // Can access private!
|
|
50
|
-
// ...
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
#[test]
|
|
54
|
-
fn test_private_helper() {
|
|
55
|
-
assert_eq!(private_helper(), 42); // Can test private!
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
## Selective Imports
|
|
61
|
-
|
|
62
|
-
```rust
|
|
63
|
-
#[cfg(test)]
|
|
64
|
-
mod tests {
|
|
65
|
-
// When you want to be explicit
|
|
66
|
-
use super::{parse, ParseError, Token};
|
|
67
|
-
|
|
68
|
-
// Or import all plus test utilities
|
|
69
|
-
use super::*;
|
|
70
|
-
use std::fs;
|
|
71
|
-
use tempfile::TempDir;
|
|
72
|
-
|
|
73
|
-
#[test]
|
|
74
|
-
fn test_parse() { ... }
|
|
75
|
-
}
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
## Nested Modules
|
|
79
|
-
|
|
80
|
-
```rust
|
|
81
|
-
mod outer {
|
|
82
|
-
pub fn outer_fn() -> i32 { 1 }
|
|
83
|
-
|
|
84
|
-
mod inner {
|
|
85
|
-
pub fn inner_fn() -> i32 { 2 }
|
|
86
|
-
|
|
87
|
-
#[cfg(test)]
|
|
88
|
-
mod tests {
|
|
89
|
-
use super::*; // Gets inner's items
|
|
90
|
-
use super::super::*; // Gets outer's items
|
|
91
|
-
|
|
92
|
-
#[test]
|
|
93
|
-
fn test_inner() {
|
|
94
|
-
assert_eq!(inner_fn(), 2);
|
|
95
|
-
assert_eq!(outer_fn(), 1);
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
## With External Dependencies
|
|
103
|
-
|
|
104
|
-
```rust
|
|
105
|
-
#[cfg(test)]
|
|
106
|
-
mod tests {
|
|
107
|
-
use super::*;
|
|
108
|
-
|
|
109
|
-
// Test-only dependencies
|
|
110
|
-
use proptest::prelude::*;
|
|
111
|
-
use mockall::predicate::*;
|
|
112
|
-
|
|
113
|
-
proptest! {
|
|
114
|
-
#[test]
|
|
115
|
-
fn test_property(s: String) {
|
|
116
|
-
let result = process(&s);
|
|
117
|
-
prop_assert!(result.is_ok());
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
## See Also
|
|
124
|
-
|
|
125
|
-
- [test-cfg-test-module](./test-cfg-test-module.md) - Test module structure
|
|
126
|
-
- [test-integration-dir](./test-integration-dir.md) - Integration tests
|
|
127
|
-
- [proj-pub-crate-internal](./proj-pub-crate-internal.md) - Visibility modifiers
|
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
# type-enum-states
|
|
2
|
-
|
|
3
|
-
> Use enums for mutually exclusive states
|
|
4
|
-
|
|
5
|
-
## Why It Matters
|
|
6
|
-
|
|
7
|
-
When a value can be in exactly one of several states, an enum makes invalid states unrepresentable. The compiler ensures all states are handled. Contrast with boolean flags or optional fields that can represent impossible combinations.
|
|
8
|
-
|
|
9
|
-
## Bad
|
|
10
|
-
|
|
11
|
-
```rust
|
|
12
|
-
struct Connection {
|
|
13
|
-
is_connected: bool,
|
|
14
|
-
is_authenticated: bool,
|
|
15
|
-
is_disconnected: bool, // Can all three be true? False?
|
|
16
|
-
socket: Option<TcpStream>,
|
|
17
|
-
credentials: Option<Credentials>,
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
// Possible invalid states:
|
|
21
|
-
// - is_connected && is_disconnected (contradiction)
|
|
22
|
-
// - is_authenticated && !is_connected (impossible)
|
|
23
|
-
// - socket is None but is_connected is true (inconsistent)
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
## Good
|
|
27
|
-
|
|
28
|
-
```rust
|
|
29
|
-
enum ConnectionState {
|
|
30
|
-
Disconnected,
|
|
31
|
-
Connecting { address: SocketAddr },
|
|
32
|
-
Connected { socket: TcpStream },
|
|
33
|
-
Authenticated { socket: TcpStream, session: Session },
|
|
34
|
-
Failed { error: ConnectionError },
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
struct Connection {
|
|
38
|
-
state: ConnectionState,
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// Impossible states are unrepresentable
|
|
42
|
-
// Each state has exactly the data it needs
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
## Pattern Matching Ensures Completeness
|
|
46
|
-
|
|
47
|
-
```rust
|
|
48
|
-
fn handle_connection(conn: &Connection) {
|
|
49
|
-
match &conn.state {
|
|
50
|
-
ConnectionState::Disconnected => {
|
|
51
|
-
println!("Not connected");
|
|
52
|
-
}
|
|
53
|
-
ConnectionState::Connecting { address } => {
|
|
54
|
-
println!("Connecting to {}", address);
|
|
55
|
-
}
|
|
56
|
-
ConnectionState::Connected { socket } => {
|
|
57
|
-
println!("Connected, not authenticated");
|
|
58
|
-
}
|
|
59
|
-
ConnectionState::Authenticated { socket, session } => {
|
|
60
|
-
println!("Authenticated as {}", session.user);
|
|
61
|
-
}
|
|
62
|
-
ConnectionState::Failed { error } => {
|
|
63
|
-
println!("Failed: {}", error);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
// Compiler error if any state is missing
|
|
67
|
-
}
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
## State Transitions
|
|
71
|
-
|
|
72
|
-
```rust
|
|
73
|
-
impl Connection {
|
|
74
|
-
fn connect(&mut self, addr: SocketAddr) -> Result<(), Error> {
|
|
75
|
-
match &self.state {
|
|
76
|
-
ConnectionState::Disconnected => {
|
|
77
|
-
self.state = ConnectionState::Connecting { address: addr };
|
|
78
|
-
Ok(())
|
|
79
|
-
}
|
|
80
|
-
_ => Err(Error::AlreadyConnected),
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
fn on_connected(&mut self, socket: TcpStream) {
|
|
85
|
-
if let ConnectionState::Connecting { .. } = &self.state {
|
|
86
|
-
self.state = ConnectionState::Connected { socket };
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
fn authenticate(&mut self, creds: Credentials) -> Result<(), Error> {
|
|
91
|
-
match std::mem::replace(&mut self.state, ConnectionState::Disconnected) {
|
|
92
|
-
ConnectionState::Connected { socket } => {
|
|
93
|
-
let session = perform_auth(&socket, creds)?;
|
|
94
|
-
self.state = ConnectionState::Authenticated { socket, session };
|
|
95
|
-
Ok(())
|
|
96
|
-
}
|
|
97
|
-
other => {
|
|
98
|
-
self.state = other;
|
|
99
|
-
Err(Error::NotConnected)
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
## Result and Option as State Enums
|
|
107
|
-
|
|
108
|
-
```rust
|
|
109
|
-
// Option<T> is an enum for "might not exist"
|
|
110
|
-
enum Option<T> {
|
|
111
|
-
Some(T),
|
|
112
|
-
None,
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// Result<T, E> is an enum for "might have failed"
|
|
116
|
-
enum Result<T, E> {
|
|
117
|
-
Ok(T),
|
|
118
|
-
Err(E),
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
// Use these instead of nullable/sentinel values
|
|
122
|
-
fn find_user(id: u64) -> Option<User> { ... }
|
|
123
|
-
fn parse_config(s: &str) -> Result<Config, ParseError> { ... }
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
## Avoid Boolean Flags
|
|
127
|
-
|
|
128
|
-
```rust
|
|
129
|
-
// Bad: boolean flags
|
|
130
|
-
struct Task {
|
|
131
|
-
is_running: bool,
|
|
132
|
-
is_completed: bool,
|
|
133
|
-
is_failed: bool,
|
|
134
|
-
error: Option<Error>,
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
// Good: enum state
|
|
138
|
-
enum TaskState {
|
|
139
|
-
Pending,
|
|
140
|
-
Running { started_at: Instant },
|
|
141
|
-
Completed { result: Output },
|
|
142
|
-
Failed { error: Error },
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
struct Task {
|
|
146
|
-
state: TaskState,
|
|
147
|
-
}
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
## See Also
|
|
151
|
-
|
|
152
|
-
- [api-typestate](./api-typestate.md) - Type-level state machines
|
|
153
|
-
- [api-non-exhaustive](./api-non-exhaustive.md) - Forward-compatible enums
|
|
154
|
-
- [type-option-nullable](./type-option-nullable.md) - Option for optional values
|
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
# type-generic-bounds
|
|
2
|
-
|
|
3
|
-
> Add trait bounds only where needed, prefer where clauses for readability
|
|
4
|
-
|
|
5
|
-
## Why It Matters
|
|
6
|
-
|
|
7
|
-
Trait bounds constrain what types can be used with generic code. Adding unnecessary bounds limits flexibility. Adding bounds in the right place (impl vs function vs where clause) affects usability and readability. Well-placed bounds keep APIs flexible while ensuring type safety.
|
|
8
|
-
|
|
9
|
-
## Bad
|
|
10
|
-
|
|
11
|
-
```rust
|
|
12
|
-
// Bounds on struct definition - limits all uses
|
|
13
|
-
struct Container<T: Clone + Debug> { // Even storage requires Clone?
|
|
14
|
-
items: Vec<T>,
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
// Inline bounds make signature hard to read
|
|
18
|
-
fn process<T: Clone + Debug + Send + Sync + 'static, E: Error + Send + Clone>(
|
|
19
|
-
value: T
|
|
20
|
-
) -> Result<T, E> { ... }
|
|
21
|
-
|
|
22
|
-
// Redundant bounds
|
|
23
|
-
fn print_twice<T: Clone + Debug>(value: T)
|
|
24
|
-
where
|
|
25
|
-
T: Clone, // Already specified above
|
|
26
|
-
{ ... }
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
## Good
|
|
30
|
-
|
|
31
|
-
```rust
|
|
32
|
-
// No bounds on struct - store anything
|
|
33
|
-
struct Container<T> {
|
|
34
|
-
items: Vec<T>,
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// Bounds only on impls that need them
|
|
38
|
-
impl<T: Clone> Container<T> {
|
|
39
|
-
fn duplicate(&self) -> Self {
|
|
40
|
-
Container { items: self.items.clone() }
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
impl<T: Debug> Container<T> {
|
|
45
|
-
fn debug_print(&self) {
|
|
46
|
-
println!("{:?}", self.items);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// Where clause for readability
|
|
51
|
-
fn process<T, E>(value: T) -> Result<T, E>
|
|
52
|
-
where
|
|
53
|
-
T: Clone + Debug + Send + Sync + 'static,
|
|
54
|
-
E: Error + Send + Clone,
|
|
55
|
-
{ ... }
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
## Bound Placement
|
|
59
|
-
|
|
60
|
-
```rust
|
|
61
|
-
// On struct: affects all uses of the type
|
|
62
|
-
struct MustBeClone<T: Clone> { data: T } // Rarely needed
|
|
63
|
-
|
|
64
|
-
// On impl: affects specific functionality
|
|
65
|
-
impl<T: Clone> Container<T> { ... } // Common pattern
|
|
66
|
-
|
|
67
|
-
// On function: affects that function only
|
|
68
|
-
fn requires_send<T: Send>(value: T) { ... }
|
|
69
|
-
|
|
70
|
-
// Recommendation: start with no bounds, add as needed
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
## Where Clause Benefits
|
|
74
|
-
|
|
75
|
-
```rust
|
|
76
|
-
// Inline: hard to read
|
|
77
|
-
fn complex<T: Clone + Debug + Send, U: AsRef<str> + Into<String>>(t: T, u: U) { }
|
|
78
|
-
|
|
79
|
-
// Where clause: clear and scannable
|
|
80
|
-
fn complex<T, U>(t: T, u: U)
|
|
81
|
-
where
|
|
82
|
-
T: Clone + Debug + Send,
|
|
83
|
-
U: AsRef<str> + Into<String>,
|
|
84
|
-
{ }
|
|
85
|
-
|
|
86
|
-
// Essential for complex bounds
|
|
87
|
-
fn foo<T, U>(t: T, u: U)
|
|
88
|
-
where
|
|
89
|
-
T: Iterator<Item = U>,
|
|
90
|
-
U: Clone + Into<String>,
|
|
91
|
-
Vec<U>: Debug, // Bounds on expressions
|
|
92
|
-
{ }
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
## Implied Bounds
|
|
96
|
-
|
|
97
|
-
```rust
|
|
98
|
-
// Supertrait bounds are implied
|
|
99
|
-
trait Foo: Clone + Debug {}
|
|
100
|
-
|
|
101
|
-
fn process<T: Foo>(value: T) {
|
|
102
|
-
// T: Clone and T: Debug are implied by T: Foo
|
|
103
|
-
let cloned = value.clone();
|
|
104
|
-
println!("{:?}", cloned);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
// Associated type bounds
|
|
108
|
-
fn process<I>(iter: I)
|
|
109
|
-
where
|
|
110
|
-
I: Iterator,
|
|
111
|
-
I::Item: Clone, // Bound on associated type
|
|
112
|
-
{ }
|
|
113
|
-
```
|
|
114
|
-
|
|
115
|
-
## Conditional Trait Implementation
|
|
116
|
-
|
|
117
|
-
```rust
|
|
118
|
-
struct Wrapper<T>(T);
|
|
119
|
-
|
|
120
|
-
// Implement Clone only when T: Clone
|
|
121
|
-
impl<T: Clone> Clone for Wrapper<T> {
|
|
122
|
-
fn clone(&self) -> Self {
|
|
123
|
-
Wrapper(self.0.clone())
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// Implement Debug only when T: Debug
|
|
128
|
-
impl<T: Debug> Debug for Wrapper<T> {
|
|
129
|
-
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
|
130
|
-
f.debug_tuple("Wrapper").field(&self.0).finish()
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// Wrapper<i32> is Clone + Debug
|
|
135
|
-
// Wrapper<NonCloneable> is neither
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
## See Also
|
|
139
|
-
|
|
140
|
-
- [api-impl-into](./api-impl-into.md) - Using Into bounds
|
|
141
|
-
- [api-impl-asref](./api-impl-asref.md) - Using AsRef bounds
|
|
142
|
-
- [name-type-param-single](./name-type-param-single.md) - Type parameter naming
|
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
# type-never-diverge
|
|
2
|
-
|
|
3
|
-
> Use `!` (never type) for functions that never return
|
|
4
|
-
|
|
5
|
-
## Why It Matters
|
|
6
|
-
|
|
7
|
-
The never type `!` indicates a function will never return normally—it either loops forever, panics, or exits the process. This helps the compiler understand control flow and enables `!` to coerce to any type, making it useful in match arms and expressions.
|
|
8
|
-
|
|
9
|
-
## Bad
|
|
10
|
-
|
|
11
|
-
```rust
|
|
12
|
-
// Return type doesn't indicate non-returning
|
|
13
|
-
fn infinite_loop() {
|
|
14
|
-
loop {
|
|
15
|
-
process_events();
|
|
16
|
-
}
|
|
17
|
-
// Implicit () return type, but never returns
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
// Using Option when it always panics
|
|
21
|
-
fn unreachable_code() -> Option<()> {
|
|
22
|
-
panic!("This should never be called");
|
|
23
|
-
}
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
## Good
|
|
27
|
-
|
|
28
|
-
```rust
|
|
29
|
-
// ! indicates function never returns
|
|
30
|
-
fn infinite_loop() -> ! {
|
|
31
|
-
loop {
|
|
32
|
-
process_events();
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
fn abort_with_error(msg: &str) -> ! {
|
|
37
|
-
eprintln!("Fatal error: {}", msg);
|
|
38
|
-
std::process::exit(1);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
fn panic_handler() -> ! {
|
|
42
|
-
panic!("Unexpected state");
|
|
43
|
-
}
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
## Coercion to Any Type
|
|
47
|
-
|
|
48
|
-
```rust
|
|
49
|
-
// ! coerces to any type
|
|
50
|
-
fn get_value(opt: Option<i32>) -> i32 {
|
|
51
|
-
match opt {
|
|
52
|
-
Some(v) => v,
|
|
53
|
-
None => panic!("No value"), // panic! returns !, coerces to i32
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// Useful in Result handling
|
|
58
|
-
fn must_get_config() -> Config {
|
|
59
|
-
match load_config() {
|
|
60
|
-
Ok(c) => c,
|
|
61
|
-
Err(e) => {
|
|
62
|
-
log_error(&e);
|
|
63
|
-
std::process::exit(1) // Returns !, coerces to Config
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
## Standard Library Examples
|
|
70
|
-
|
|
71
|
-
```rust
|
|
72
|
-
// std::process::exit
|
|
73
|
-
pub fn exit(code: i32) -> !
|
|
74
|
-
|
|
75
|
-
// panic! macro
|
|
76
|
-
// Expands to an expression of type !
|
|
77
|
-
|
|
78
|
-
// std::hint::unreachable_unchecked
|
|
79
|
-
pub unsafe fn unreachable_unchecked() -> !
|
|
80
|
-
|
|
81
|
-
// loop {} with no break
|
|
82
|
-
fn forever() -> ! {
|
|
83
|
-
loop {}
|
|
84
|
-
}
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
## In Match Expressions
|
|
88
|
-
|
|
89
|
-
```rust
|
|
90
|
-
enum State {
|
|
91
|
-
Running,
|
|
92
|
-
Stopped,
|
|
93
|
-
Error,
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
fn get_status(state: &State) -> &str {
|
|
97
|
-
match state {
|
|
98
|
-
State::Running => "running",
|
|
99
|
-
State::Stopped => "stopped",
|
|
100
|
-
State::Error => unreachable!(), // ! coerces to &str
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// With Result
|
|
105
|
-
fn process(r: Result<Data, Error>) -> Data {
|
|
106
|
-
match r {
|
|
107
|
-
Ok(d) => d,
|
|
108
|
-
Err(e) => panic!("Unexpected error: {}", e), // ! coerces to Data
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
## Diverging Closures
|
|
114
|
-
|
|
115
|
-
```rust
|
|
116
|
-
// Closures that never return
|
|
117
|
-
let handler: fn() -> ! = || {
|
|
118
|
-
panic!("Handler called");
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
// In thread spawn
|
|
122
|
-
std::thread::spawn(|| -> ! {
|
|
123
|
-
loop {
|
|
124
|
-
process_work();
|
|
125
|
-
}
|
|
126
|
-
});
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
## Current Limitations (Nightly)
|
|
130
|
-
|
|
131
|
-
```rust
|
|
132
|
-
// Full ! type is nightly
|
|
133
|
-
#![feature(never_type)]
|
|
134
|
-
|
|
135
|
-
// Can use ! as type parameter
|
|
136
|
-
type NeverResult = Result<(), !>; // Can never be Err
|
|
137
|
-
|
|
138
|
-
// On stable, use std::convert::Infallible
|
|
139
|
-
type StableNeverResult = Result<(), std::convert::Infallible>;
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
## See Also
|
|
143
|
-
|
|
144
|
-
- [err-result-over-panic](./err-result-over-panic.md) - When to panic vs return Result
|
|
145
|
-
- [type-result-fallible](./type-result-fallible.md) - Result for errors
|
|
146
|
-
- [opt-cold-unlikely](./opt-cold-unlikely.md) - Marking unlikely paths
|