agy-superpowers 5.2.2 → 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/rules/scratch-scripts.md +37 -0
- package/template/agent/rules/superpowers.md +4 -51
- 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,130 +0,0 @@
|
|
|
1
|
-
# test-should-panic
|
|
2
|
-
|
|
3
|
-
> Use `#[should_panic]` to test that code panics as expected
|
|
4
|
-
|
|
5
|
-
## Why It Matters
|
|
6
|
-
|
|
7
|
-
Some code should panic on invalid inputs or invariant violations. `#[should_panic]` verifies the panic occurs, optionally checking the panic message. This ensures defensive panics work correctly and documents expected panic conditions.
|
|
8
|
-
|
|
9
|
-
## Bad
|
|
10
|
-
|
|
11
|
-
```rust
|
|
12
|
-
#[test]
|
|
13
|
-
fn test_panic() {
|
|
14
|
-
// Just calling panicking code makes test fail
|
|
15
|
-
divide(1, 0); // Test fails with panic
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
// Using catch_unwind is verbose
|
|
19
|
-
#[test]
|
|
20
|
-
fn test_panic_manual() {
|
|
21
|
-
let result = std::panic::catch_unwind(|| divide(1, 0));
|
|
22
|
-
assert!(result.is_err());
|
|
23
|
-
}
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
## Good
|
|
27
|
-
|
|
28
|
-
```rust
|
|
29
|
-
#[test]
|
|
30
|
-
#[should_panic]
|
|
31
|
-
fn divide_by_zero_panics() {
|
|
32
|
-
divide(1, 0); // Test passes when this panics
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// With expected message
|
|
36
|
-
#[test]
|
|
37
|
-
#[should_panic(expected = "division by zero")]
|
|
38
|
-
fn divide_by_zero_panics_with_message() {
|
|
39
|
-
divide(1, 0); // Panics with "division by zero"
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// Partial message match
|
|
43
|
-
#[test]
|
|
44
|
-
#[should_panic(expected = "index out of bounds")]
|
|
45
|
-
fn index_panic_contains_message() {
|
|
46
|
-
let v = vec![1, 2, 3];
|
|
47
|
-
let _ = v[100]; // Message contains "index out of bounds"
|
|
48
|
-
}
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
## Testing Invariants
|
|
52
|
-
|
|
53
|
-
```rust
|
|
54
|
-
struct NonEmpty<T>(Vec<T>);
|
|
55
|
-
|
|
56
|
-
impl<T> NonEmpty<T> {
|
|
57
|
-
fn new(items: Vec<T>) -> Self {
|
|
58
|
-
assert!(!items.is_empty(), "NonEmpty cannot be empty");
|
|
59
|
-
NonEmpty(items)
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
#[test]
|
|
64
|
-
#[should_panic(expected = "NonEmpty cannot be empty")]
|
|
65
|
-
fn non_empty_rejects_empty_vec() {
|
|
66
|
-
NonEmpty::new(Vec::<i32>::new());
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
#[test]
|
|
70
|
-
fn non_empty_accepts_non_empty_vec() {
|
|
71
|
-
let ne = NonEmpty::new(vec![1, 2, 3]);
|
|
72
|
-
assert_eq!(ne.0.len(), 3);
|
|
73
|
-
}
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
## With expect() Messages
|
|
77
|
-
|
|
78
|
-
```rust
|
|
79
|
-
fn get_config_value(key: &str) -> String {
|
|
80
|
-
CONFIG.get(key)
|
|
81
|
-
.expect(&format!("missing required config: {}", key))
|
|
82
|
-
.to_string()
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
#[test]
|
|
86
|
-
#[should_panic(expected = "missing required config: DATABASE_URL")]
|
|
87
|
-
fn missing_config_panics_with_key() {
|
|
88
|
-
get_config_value("DATABASE_URL");
|
|
89
|
-
}
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
## When NOT to Use should_panic
|
|
93
|
-
|
|
94
|
-
```rust
|
|
95
|
-
// ❌ For recoverable errors - use Result
|
|
96
|
-
#[test]
|
|
97
|
-
#[should_panic] // Wrong: this should return Err, not panic
|
|
98
|
-
fn invalid_input_panics() {
|
|
99
|
-
parse_config("invalid"); // Should return Err, not panic
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// ✅ Return Result and test the error
|
|
103
|
-
#[test]
|
|
104
|
-
fn invalid_input_returns_error() {
|
|
105
|
-
let result = parse_config("invalid");
|
|
106
|
-
assert!(result.is_err());
|
|
107
|
-
}
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
## Combining with Result
|
|
111
|
-
|
|
112
|
-
```rust
|
|
113
|
-
#[test]
|
|
114
|
-
#[should_panic]
|
|
115
|
-
fn test_panics() -> Result<(), Error> {
|
|
116
|
-
// Can combine with Result for setup
|
|
117
|
-
let data = setup_test_data()?;
|
|
118
|
-
|
|
119
|
-
// This should panic
|
|
120
|
-
process_invalid(&data);
|
|
121
|
-
|
|
122
|
-
Ok(()) // Never reached
|
|
123
|
-
}
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
## See Also
|
|
127
|
-
|
|
128
|
-
- [err-result-over-panic](./err-result-over-panic.md) - Panic vs Result
|
|
129
|
-
- [err-expect-bugs-only](./err-expect-bugs-only.md) - When to use expect
|
|
130
|
-
- [test-descriptive-names](./test-descriptive-names.md) - Test naming
|
|
@@ -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
|