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,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
|
|
@@ -1,160 +0,0 @@
|
|
|
1
|
-
# type-newtype-ids
|
|
2
|
-
|
|
3
|
-
> Wrap IDs in newtypes: `UserId(u64)`
|
|
4
|
-
|
|
5
|
-
## Why It Matters
|
|
6
|
-
|
|
7
|
-
Using raw integers for IDs is error-prone. It's easy to accidentally pass a `user_id` where a `post_id` is expected. Newtypes make these mix-ups compile-time errors instead of runtime bugs.
|
|
8
|
-
|
|
9
|
-
## Bad
|
|
10
|
-
|
|
11
|
-
```rust
|
|
12
|
-
fn get_user_posts(user_id: u64, post_id: u64) -> Vec<Post> {
|
|
13
|
-
// Which is which? Easy to swap by accident
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
// Oops! Arguments swapped - compiles fine, wrong at runtime
|
|
17
|
-
let posts = get_user_posts(post_id, user_id);
|
|
18
|
-
|
|
19
|
-
// Even worse with multiple IDs
|
|
20
|
-
fn transfer(from: u64, to: u64, amount: u64) {
|
|
21
|
-
// from/to can easily be swapped
|
|
22
|
-
}
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
## Good
|
|
26
|
-
|
|
27
|
-
```rust
|
|
28
|
-
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
|
29
|
-
pub struct UserId(pub u64);
|
|
30
|
-
|
|
31
|
-
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
|
32
|
-
pub struct PostId(pub u64);
|
|
33
|
-
|
|
34
|
-
fn get_user_posts(user_id: UserId, post_id: PostId) -> Vec<Post> {
|
|
35
|
-
// Types are distinct
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// This won't compile - types don't match
|
|
39
|
-
// let posts = get_user_posts(post_id, user_id); // ERROR!
|
|
40
|
-
|
|
41
|
-
// Correct usage
|
|
42
|
-
let posts = get_user_posts(UserId(1), PostId(42));
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
## Derive Common Traits
|
|
46
|
-
|
|
47
|
-
```rust
|
|
48
|
-
#[derive(
|
|
49
|
-
Debug, // For printing
|
|
50
|
-
Clone, // For copying
|
|
51
|
-
Copy, // For implicit copies (if small)
|
|
52
|
-
PartialEq, // For == comparison
|
|
53
|
-
Eq, // For HashMap keys
|
|
54
|
-
Hash, // For HashMap keys
|
|
55
|
-
PartialOrd, // For sorting (optional)
|
|
56
|
-
Ord, // For BTreeMap keys (optional)
|
|
57
|
-
)]
|
|
58
|
-
pub struct UserId(pub u64);
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
## Add Useful Methods
|
|
62
|
-
|
|
63
|
-
```rust
|
|
64
|
-
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
|
65
|
-
pub struct UserId(u64);
|
|
66
|
-
|
|
67
|
-
impl UserId {
|
|
68
|
-
pub const fn new(id: u64) -> Self {
|
|
69
|
-
Self(id)
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
pub const fn get(self) -> u64 {
|
|
73
|
-
self.0
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// For database queries
|
|
77
|
-
pub fn as_i64(self) -> i64 {
|
|
78
|
-
self.0 as i64
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
impl From<u64> for UserId {
|
|
83
|
-
fn from(id: u64) -> Self {
|
|
84
|
-
Self(id)
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
impl std::fmt::Display for UserId {
|
|
89
|
-
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
90
|
-
write!(f, "user:{}", self.0)
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
## With Serde
|
|
96
|
-
|
|
97
|
-
```rust
|
|
98
|
-
use serde::{Deserialize, Serialize};
|
|
99
|
-
|
|
100
|
-
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
|
101
|
-
#[serde(transparent)] // Serializes as just the inner value
|
|
102
|
-
pub struct UserId(pub u64);
|
|
103
|
-
|
|
104
|
-
// JSON: {"user_id": 123} not {"user_id": {"0": 123}}
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
## String IDs (UUIDs, etc.)
|
|
108
|
-
|
|
109
|
-
```rust
|
|
110
|
-
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
|
111
|
-
pub struct SessionId(String);
|
|
112
|
-
|
|
113
|
-
impl SessionId {
|
|
114
|
-
pub fn new() -> Self {
|
|
115
|
-
Self(uuid::Uuid::new_v4().to_string())
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
pub fn parse(s: &str) -> Result<Self, ParseError> {
|
|
119
|
-
// Validate format
|
|
120
|
-
uuid::Uuid::parse_str(s)?;
|
|
121
|
-
Ok(Self(s.to_string()))
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
pub fn as_str(&self) -> &str {
|
|
125
|
-
&self.0
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
## Multiple Related IDs
|
|
131
|
-
|
|
132
|
-
```rust
|
|
133
|
-
// Macro for consistent ID types
|
|
134
|
-
macro_rules! define_id {
|
|
135
|
-
($name:ident) => {
|
|
136
|
-
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
|
137
|
-
pub struct $name(pub u64);
|
|
138
|
-
|
|
139
|
-
impl $name {
|
|
140
|
-
pub const fn new(id: u64) -> Self { Self(id) }
|
|
141
|
-
pub const fn get(self) -> u64 { self.0 }
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
impl From<u64> for $name {
|
|
145
|
-
fn from(id: u64) -> Self { Self(id) }
|
|
146
|
-
}
|
|
147
|
-
};
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
define_id!(UserId);
|
|
151
|
-
define_id!(PostId);
|
|
152
|
-
define_id!(CommentId);
|
|
153
|
-
define_id!(TeamId);
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
## See Also
|
|
157
|
-
|
|
158
|
-
- [api-newtype-safety](api-newtype-safety.md) - Newtypes for type safety
|
|
159
|
-
- [type-newtype-validated](type-newtype-validated.md) - Newtypes for validated data
|
|
160
|
-
- [api-parse-dont-validate](api-parse-dont-validate.md) - Parse into validated types
|
package/template/agent/skills/rust-developer/references/rust-rules/type-newtype-validated.md
DELETED
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
# type-newtype-validated
|
|
2
|
-
|
|
3
|
-
> Use newtypes to enforce validation at construction time
|
|
4
|
-
|
|
5
|
-
## Why It Matters
|
|
6
|
-
|
|
7
|
-
A validated newtype guarantees its inner value is always valid. Once you have an `Email`, you know it passed validation—no re-checking needed. This "parse, don't validate" pattern catches errors at boundaries and makes invalid states unrepresentable.
|
|
8
|
-
|
|
9
|
-
## Bad
|
|
10
|
-
|
|
11
|
-
```rust
|
|
12
|
-
// Validation scattered throughout code
|
|
13
|
-
fn send_email(to: &str, body: &str) -> Result<(), Error> {
|
|
14
|
-
if !is_valid_email(to) { // Must check every time
|
|
15
|
-
return Err(Error::InvalidEmail);
|
|
16
|
-
}
|
|
17
|
-
// ...
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
fn add_recipient(list: &mut Vec<String>, email: &str) -> Result<(), Error> {
|
|
21
|
-
if !is_valid_email(email) { // Check again
|
|
22
|
-
return Err(Error::InvalidEmail);
|
|
23
|
-
}
|
|
24
|
-
list.push(email.to_string());
|
|
25
|
-
Ok(())
|
|
26
|
-
}
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
## Good
|
|
30
|
-
|
|
31
|
-
```rust
|
|
32
|
-
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
|
33
|
-
pub struct Email(String);
|
|
34
|
-
|
|
35
|
-
impl Email {
|
|
36
|
-
pub fn new(s: &str) -> Result<Self, EmailError> {
|
|
37
|
-
if is_valid_email(s) {
|
|
38
|
-
Ok(Email(s.to_string()))
|
|
39
|
-
} else {
|
|
40
|
-
Err(EmailError::Invalid(s.to_string()))
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
pub fn as_str(&self) -> &str {
|
|
45
|
-
&self.0
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// No validation needed - Email is always valid
|
|
50
|
-
fn send_email(to: &Email, body: &str) -> Result<(), Error> {
|
|
51
|
-
// to is guaranteed valid
|
|
52
|
-
send_to_address(to.as_str(), body)
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
fn add_recipient(list: &mut Vec<Email>, email: Email) {
|
|
56
|
-
// email is guaranteed valid
|
|
57
|
-
list.push(email);
|
|
58
|
-
}
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
## Common Validated Types
|
|
62
|
-
|
|
63
|
-
```rust
|
|
64
|
-
// URLs
|
|
65
|
-
pub struct Url(url::Url);
|
|
66
|
-
|
|
67
|
-
impl Url {
|
|
68
|
-
pub fn parse(s: &str) -> Result<Self, UrlError> {
|
|
69
|
-
url::Url::parse(s)
|
|
70
|
-
.map(Url)
|
|
71
|
-
.map_err(UrlError::from)
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// Non-empty strings
|
|
76
|
-
pub struct NonEmptyString(String);
|
|
77
|
-
|
|
78
|
-
impl NonEmptyString {
|
|
79
|
-
pub fn new(s: String) -> Option<Self> {
|
|
80
|
-
if s.is_empty() {
|
|
81
|
-
None
|
|
82
|
-
} else {
|
|
83
|
-
Some(NonEmptyString(s))
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
// Positive numbers
|
|
89
|
-
pub struct PositiveI32(i32);
|
|
90
|
-
|
|
91
|
-
impl PositiveI32 {
|
|
92
|
-
pub fn new(n: i32) -> Option<Self> {
|
|
93
|
-
if n > 0 {
|
|
94
|
-
Some(PositiveI32(n))
|
|
95
|
-
} else {
|
|
96
|
-
None
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
pub fn get(&self) -> i32 {
|
|
101
|
-
self.0
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// Bounded ranges
|
|
106
|
-
pub struct Percentage(f64);
|
|
107
|
-
|
|
108
|
-
impl Percentage {
|
|
109
|
-
pub fn new(value: f64) -> Result<Self, RangeError> {
|
|
110
|
-
if (0.0..=100.0).contains(&value) {
|
|
111
|
-
Ok(Percentage(value))
|
|
112
|
-
} else {
|
|
113
|
-
Err(RangeError::OutOfBounds)
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
## With Serde
|
|
120
|
-
|
|
121
|
-
```rust
|
|
122
|
-
use serde::{Deserialize, Serialize};
|
|
123
|
-
|
|
124
|
-
#[derive(Debug, Clone, Serialize)]
|
|
125
|
-
pub struct Email(String);
|
|
126
|
-
|
|
127
|
-
impl<'de> Deserialize<'de> for Email {
|
|
128
|
-
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
129
|
-
where
|
|
130
|
-
D: serde::Deserializer<'de>,
|
|
131
|
-
{
|
|
132
|
-
let s = String::deserialize(deserializer)?;
|
|
133
|
-
Email::new(&s).map_err(serde::de::Error::custom)
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
// JSON deserialization automatically validates
|
|
138
|
-
let email: Email = serde_json::from_str(r#""user@example.com""#)?;
|
|
139
|
-
```
|
|
140
|
-
|
|
141
|
-
## Compile-Time Validation
|
|
142
|
-
|
|
143
|
-
```rust
|
|
144
|
-
// For values known at compile time
|
|
145
|
-
macro_rules! email {
|
|
146
|
-
($s:literal) => {{
|
|
147
|
-
const _: () = assert!(is_valid_email_const($s));
|
|
148
|
-
Email::new_unchecked($s)
|
|
149
|
-
}};
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
let admin = email!("admin@example.com"); // Validated at compile time
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
## See Also
|
|
156
|
-
|
|
157
|
-
- [api-parse-dont-validate](./api-parse-dont-validate.md) - Parse at boundaries
|
|
158
|
-
- [api-newtype-safety](./api-newtype-safety.md) - Type-safe distinctions
|
|
159
|
-
- [type-newtype-ids](./type-newtype-ids.md) - ID newtypes
|
|
@@ -1,144 +0,0 @@
|
|
|
1
|
-
# type-no-stringly
|
|
2
|
-
|
|
3
|
-
> Avoid stringly-typed APIs; use enums, newtypes, or validated types
|
|
4
|
-
|
|
5
|
-
## Why It Matters
|
|
6
|
-
|
|
7
|
-
Strings accept any value—typos, wrong formats, invalid data all compile fine. Enums, newtypes, and validated types catch errors at compile time or construction time, not runtime. They also provide better IDE support, documentation, and make invalid states unrepresentable.
|
|
8
|
-
|
|
9
|
-
## Bad
|
|
10
|
-
|
|
11
|
-
```rust
|
|
12
|
-
// Status as string - easy to get wrong
|
|
13
|
-
fn set_status(status: &str) {
|
|
14
|
-
match status {
|
|
15
|
-
"pending" => { ... }
|
|
16
|
-
"active" => { ... }
|
|
17
|
-
"completed" => { ... }
|
|
18
|
-
_ => panic!("Unknown status"), // Runtime error
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
// Easy to misuse
|
|
23
|
-
set_status("pending"); // OK
|
|
24
|
-
set_status("Pending"); // Runtime error - wrong case
|
|
25
|
-
set_status("aktive"); // Runtime error - typo
|
|
26
|
-
set_status("done"); // Runtime error - wrong word
|
|
27
|
-
|
|
28
|
-
// Configuration as strings
|
|
29
|
-
fn configure(key: &str, value: &str) {
|
|
30
|
-
// No type safety, no validation
|
|
31
|
-
}
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
## Good
|
|
35
|
-
|
|
36
|
-
```rust
|
|
37
|
-
// Status as enum - compile-time safety
|
|
38
|
-
enum Status {
|
|
39
|
-
Pending,
|
|
40
|
-
Active,
|
|
41
|
-
Completed,
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
fn set_status(status: Status) {
|
|
45
|
-
match status {
|
|
46
|
-
Status::Pending => { ... }
|
|
47
|
-
Status::Active => { ... }
|
|
48
|
-
Status::Completed => { ... }
|
|
49
|
-
} // Exhaustive - compiler checks all cases
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// Can only pass valid values
|
|
53
|
-
set_status(Status::Pending); // OK
|
|
54
|
-
set_status(Status::Aktivev); // Compile error - typo caught!
|
|
55
|
-
|
|
56
|
-
// Configuration with typed builder
|
|
57
|
-
struct Config {
|
|
58
|
-
timeout: Duration,
|
|
59
|
-
retries: u32,
|
|
60
|
-
mode: Mode,
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
enum Mode { Fast, Safe, Balanced }
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
## Parsing at Boundaries
|
|
67
|
-
|
|
68
|
-
```rust
|
|
69
|
-
use std::str::FromStr;
|
|
70
|
-
|
|
71
|
-
#[derive(Debug, Clone, Copy)]
|
|
72
|
-
enum Priority {
|
|
73
|
-
Low,
|
|
74
|
-
Medium,
|
|
75
|
-
High,
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
impl FromStr for Priority {
|
|
79
|
-
type Err = ParseError;
|
|
80
|
-
|
|
81
|
-
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
82
|
-
match s.to_lowercase().as_str() {
|
|
83
|
-
"low" => Ok(Priority::Low),
|
|
84
|
-
"medium" | "med" => Ok(Priority::Medium),
|
|
85
|
-
"high" => Ok(Priority::High),
|
|
86
|
-
_ => Err(ParseError::UnknownPriority(s.to_string())),
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
// Parse once at boundary
|
|
92
|
-
fn handle_request(priority_str: &str) -> Result<(), Error> {
|
|
93
|
-
let priority: Priority = priority_str.parse()?;
|
|
94
|
-
// From here, priority is type-safe
|
|
95
|
-
process(priority);
|
|
96
|
-
Ok(())
|
|
97
|
-
}
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
## Validated Newtypes
|
|
101
|
-
|
|
102
|
-
```rust
|
|
103
|
-
// Instead of string for email
|
|
104
|
-
struct Email(String);
|
|
105
|
-
|
|
106
|
-
impl Email {
|
|
107
|
-
fn new(s: &str) -> Result<Self, ValidationError> {
|
|
108
|
-
if is_valid_email(s) {
|
|
109
|
-
Ok(Email(s.to_string()))
|
|
110
|
-
} else {
|
|
111
|
-
Err(ValidationError::InvalidEmail)
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
// Instead of string for UUID
|
|
117
|
-
struct UserId(uuid::Uuid);
|
|
118
|
-
|
|
119
|
-
// Instead of string for paths
|
|
120
|
-
struct ConfigPath(PathBuf);
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
## With Serde
|
|
124
|
-
|
|
125
|
-
```rust
|
|
126
|
-
use serde::{Deserialize, Serialize};
|
|
127
|
-
|
|
128
|
-
#[derive(Debug, Serialize, Deserialize)]
|
|
129
|
-
#[serde(rename_all = "snake_case")]
|
|
130
|
-
enum EventType {
|
|
131
|
-
UserCreated,
|
|
132
|
-
UserDeleted,
|
|
133
|
-
UserUpdated,
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
// JSON: {"type": "user_created", ...}
|
|
137
|
-
// Automatically validated during deserialization
|
|
138
|
-
```
|
|
139
|
-
|
|
140
|
-
## See Also
|
|
141
|
-
|
|
142
|
-
- [anti-stringly-typed](./anti-stringly-typed.md) - Anti-pattern details
|
|
143
|
-
- [type-newtype-validated](./type-newtype-validated.md) - Validated newtypes
|
|
144
|
-
- [type-enum-states](./type-enum-states.md) - Enums for states
|