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,137 +0,0 @@
|
|
|
1
|
-
# type-option-nullable
|
|
2
|
-
|
|
3
|
-
> Use `Option<T>` for values that might not exist
|
|
4
|
-
|
|
5
|
-
## Why It Matters
|
|
6
|
-
|
|
7
|
-
`Option<T>` explicitly represents "value or nothing" in the type system. Unlike null pointers or sentinel values, you can't accidentally use a missing value—the compiler forces you to handle the `None` case. This eliminates null pointer exceptions at compile time.
|
|
8
|
-
|
|
9
|
-
## Bad
|
|
10
|
-
|
|
11
|
-
```rust
|
|
12
|
-
// Sentinel values - easy to forget to check
|
|
13
|
-
fn find_user(id: u64) -> User {
|
|
14
|
-
// Returns "empty" user if not found - caller might not check
|
|
15
|
-
users.get(&id).cloned().unwrap_or(User::empty())
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
// Nullable-style with raw pointers
|
|
19
|
-
fn find_user(id: u64) -> *const User {
|
|
20
|
-
// Null if not found - unsafe, no compiler help
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
// Error-prone usage
|
|
24
|
-
let user = find_user(42);
|
|
25
|
-
println!("{}", user.name); // Might be empty user - silent bug
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
## Good
|
|
29
|
-
|
|
30
|
-
```rust
|
|
31
|
-
// Option makes absence explicit
|
|
32
|
-
fn find_user(id: u64) -> Option<User> {
|
|
33
|
-
users.get(&id).cloned()
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// Must handle the None case
|
|
37
|
-
let user = find_user(42);
|
|
38
|
-
match user {
|
|
39
|
-
Some(u) => println!("{}", u.name),
|
|
40
|
-
None => println!("User not found"),
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// Or use combinators
|
|
44
|
-
let name = find_user(42)
|
|
45
|
-
.map(|u| u.name)
|
|
46
|
-
.unwrap_or_else(|| "Unknown".to_string());
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
## Common Option Patterns
|
|
50
|
-
|
|
51
|
-
```rust
|
|
52
|
-
// if let for single case
|
|
53
|
-
if let Some(user) = find_user(id) {
|
|
54
|
-
process(user);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// Chaining with map
|
|
58
|
-
let upper_name = find_user(id)
|
|
59
|
-
.map(|u| u.name)
|
|
60
|
-
.map(|n| n.to_uppercase());
|
|
61
|
-
|
|
62
|
-
// Providing defaults
|
|
63
|
-
let user = find_user(id).unwrap_or_default();
|
|
64
|
-
let user = find_user(id).unwrap_or_else(|| User::guest());
|
|
65
|
-
|
|
66
|
-
// ? operator for propagation
|
|
67
|
-
fn get_user_email(id: u64) -> Option<String> {
|
|
68
|
-
let user = find_user(id)?;
|
|
69
|
-
Some(user.email)
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// and_then for chained optionals
|
|
73
|
-
fn get_user_country(id: u64) -> Option<String> {
|
|
74
|
-
find_user(id)
|
|
75
|
-
.and_then(|u| u.address)
|
|
76
|
-
.and_then(|a| a.country)
|
|
77
|
-
}
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
## Struct Fields
|
|
81
|
-
|
|
82
|
-
```rust
|
|
83
|
-
struct User {
|
|
84
|
-
name: String,
|
|
85
|
-
email: String,
|
|
86
|
-
phone: Option<String>, // Optional field
|
|
87
|
-
avatar_url: Option<Url>, // Optional field
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
impl User {
|
|
91
|
-
fn display_phone(&self) -> &str {
|
|
92
|
-
self.phone.as_deref().unwrap_or("Not provided")
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
## Option vs Result
|
|
98
|
-
|
|
99
|
-
```rust
|
|
100
|
-
// Option: value might not exist (no error context)
|
|
101
|
-
fn find(key: &str) -> Option<Value> { ... }
|
|
102
|
-
|
|
103
|
-
// Result: operation might fail (with error context)
|
|
104
|
-
fn parse(input: &str) -> Result<Value, ParseError> { ... }
|
|
105
|
-
|
|
106
|
-
// Convert Option to Result
|
|
107
|
-
let value = find("key").ok_or(Error::NotFound)?;
|
|
108
|
-
|
|
109
|
-
// Convert Result to Option
|
|
110
|
-
let value = parse("input").ok(); // Discards error
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
## Option References
|
|
114
|
-
|
|
115
|
-
```rust
|
|
116
|
-
// Option<&T> for optional borrows
|
|
117
|
-
fn get(&self, key: &str) -> Option<&Value> {
|
|
118
|
-
self.map.get(key)
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
// as_ref() to borrow Option contents
|
|
122
|
-
let opt: Option<String> = Some("hello".to_string());
|
|
123
|
-
let opt_ref: Option<&String> = opt.as_ref();
|
|
124
|
-
let opt_str: Option<&str> = opt.as_deref();
|
|
125
|
-
|
|
126
|
-
// as_mut() for mutable borrow
|
|
127
|
-
let mut opt = Some(vec![1, 2, 3]);
|
|
128
|
-
if let Some(v) = opt.as_mut() {
|
|
129
|
-
v.push(4);
|
|
130
|
-
}
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
## See Also
|
|
134
|
-
|
|
135
|
-
- [type-result-fallible](./type-result-fallible.md) - Result for errors
|
|
136
|
-
- [type-enum-states](./type-enum-states.md) - Enums for states
|
|
137
|
-
- [err-no-unwrap-prod](./err-no-unwrap-prod.md) - Handling Option safely
|
|
@@ -1,188 +0,0 @@
|
|
|
1
|
-
# type-phantom-marker
|
|
2
|
-
|
|
3
|
-
> Use `PhantomData` to express type relationships without runtime cost
|
|
4
|
-
|
|
5
|
-
## Why It Matters
|
|
6
|
-
|
|
7
|
-
Sometimes your type needs to be parameterized by a type that doesn't appear in any field—for variance, drop order, or semantic purposes. `PhantomData<T>` tells the compiler your type is "associated with" `T` without storing any `T` data. It has zero runtime cost.
|
|
8
|
-
|
|
9
|
-
## Bad
|
|
10
|
-
|
|
11
|
-
```rust
|
|
12
|
-
// Type parameter unused - compiler error
|
|
13
|
-
struct Handle<T> {
|
|
14
|
-
id: u64,
|
|
15
|
-
// Error: parameter `T` is never used
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
// Workaround with unnecessary storage
|
|
19
|
-
struct Handle<T> {
|
|
20
|
-
id: u64,
|
|
21
|
-
_type: Option<T>, // Wastes memory, requires T: Default
|
|
22
|
-
}
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
## Good
|
|
26
|
-
|
|
27
|
-
```rust
|
|
28
|
-
use std::marker::PhantomData;
|
|
29
|
-
|
|
30
|
-
struct Handle<T> {
|
|
31
|
-
id: u64,
|
|
32
|
-
_marker: PhantomData<T>, // Zero-size, tells compiler about T
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
impl<T> Handle<T> {
|
|
36
|
-
fn new(id: u64) -> Self {
|
|
37
|
-
Handle {
|
|
38
|
-
id,
|
|
39
|
-
_marker: PhantomData,
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// Different Handle types are incompatible
|
|
45
|
-
struct User;
|
|
46
|
-
struct Order;
|
|
47
|
-
|
|
48
|
-
fn process_user(h: Handle<User>) { ... }
|
|
49
|
-
|
|
50
|
-
let user_handle = Handle::<User>::new(1);
|
|
51
|
-
let order_handle = Handle::<Order>::new(2);
|
|
52
|
-
|
|
53
|
-
process_user(user_handle); // OK
|
|
54
|
-
process_user(order_handle); // Error: expected Handle<User>, found Handle<Order>
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
## Expressing Ownership
|
|
58
|
-
|
|
59
|
-
```rust
|
|
60
|
-
use std::marker::PhantomData;
|
|
61
|
-
|
|
62
|
-
// Owns T conceptually (like Box<T>)
|
|
63
|
-
struct Container<T> {
|
|
64
|
-
ptr: *mut T,
|
|
65
|
-
_marker: PhantomData<T>, // Acts like we own a T
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// Drop will be called on T when Container drops
|
|
69
|
-
impl<T> Drop for Container<T> {
|
|
70
|
-
fn drop(&mut self) {
|
|
71
|
-
unsafe {
|
|
72
|
-
std::ptr::drop_in_place(self.ptr);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
## Expressing Borrowing
|
|
79
|
-
|
|
80
|
-
```rust
|
|
81
|
-
use std::marker::PhantomData;
|
|
82
|
-
|
|
83
|
-
// Borrows T for lifetime 'a
|
|
84
|
-
struct Ref<'a, T> {
|
|
85
|
-
ptr: *const T,
|
|
86
|
-
_marker: PhantomData<&'a T>, // Acts like &'a T
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// Compiler tracks lifetime correctly
|
|
90
|
-
impl<'a, T> Ref<'a, T> {
|
|
91
|
-
fn get(&self) -> &'a T {
|
|
92
|
-
unsafe { &*self.ptr }
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
## Type-Level State Machine
|
|
98
|
-
|
|
99
|
-
```rust
|
|
100
|
-
use std::marker::PhantomData;
|
|
101
|
-
|
|
102
|
-
// States as zero-size types
|
|
103
|
-
struct Unlocked;
|
|
104
|
-
struct Locked;
|
|
105
|
-
|
|
106
|
-
struct Door<State> {
|
|
107
|
-
_state: PhantomData<State>,
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
impl Door<Unlocked> {
|
|
111
|
-
fn lock(self) -> Door<Locked> {
|
|
112
|
-
println!("Locking...");
|
|
113
|
-
Door { _state: PhantomData }
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
fn open(&self) {
|
|
117
|
-
println!("Opening...");
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
impl Door<Locked> {
|
|
122
|
-
fn unlock(self) -> Door<Unlocked> {
|
|
123
|
-
println!("Unlocking...");
|
|
124
|
-
Door { _state: PhantomData }
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// Can't call open() on Locked door - method doesn't exist
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
fn example() {
|
|
131
|
-
let door: Door<Unlocked> = Door { _state: PhantomData };
|
|
132
|
-
door.open(); // OK
|
|
133
|
-
let locked = door.lock();
|
|
134
|
-
// locked.open(); // Error: no method `open` for Door<Locked>
|
|
135
|
-
let unlocked = locked.unlock();
|
|
136
|
-
unlocked.open(); // OK
|
|
137
|
-
}
|
|
138
|
-
```
|
|
139
|
-
|
|
140
|
-
## Variance Control
|
|
141
|
-
|
|
142
|
-
```rust
|
|
143
|
-
use std::marker::PhantomData;
|
|
144
|
-
|
|
145
|
-
// Covariant in T (PhantomData<T>)
|
|
146
|
-
struct Producer<T> {
|
|
147
|
-
_marker: PhantomData<T>, // Covariant
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
// Contravariant in T (PhantomData<fn(T)>)
|
|
151
|
-
struct Consumer<T> {
|
|
152
|
-
_marker: PhantomData<fn(T)>, // Contravariant
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// Invariant in T (PhantomData<fn(T) -> T>)
|
|
156
|
-
struct Both<T> {
|
|
157
|
-
_marker: PhantomData<fn(T) -> T>, // Invariant
|
|
158
|
-
}
|
|
159
|
-
```
|
|
160
|
-
|
|
161
|
-
## Common Uses
|
|
162
|
-
|
|
163
|
-
```rust
|
|
164
|
-
// 1. FFI handles with type safety
|
|
165
|
-
struct FileHandle<T: FileType> {
|
|
166
|
-
fd: i32,
|
|
167
|
-
_marker: PhantomData<T>,
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
// 2. Generic iterators
|
|
171
|
-
struct Iter<'a, T> {
|
|
172
|
-
ptr: *const T,
|
|
173
|
-
end: *const T,
|
|
174
|
-
_marker: PhantomData<&'a T>,
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
// 3. Allocator-aware types
|
|
178
|
-
struct Vec<T, A: Allocator = Global> {
|
|
179
|
-
buf: RawVec<T, A>,
|
|
180
|
-
len: usize,
|
|
181
|
-
}
|
|
182
|
-
```
|
|
183
|
-
|
|
184
|
-
## See Also
|
|
185
|
-
|
|
186
|
-
- [api-typestate](./api-typestate.md) - State machine pattern
|
|
187
|
-
- [api-newtype-safety](./api-newtype-safety.md) - Type-safe wrappers
|
|
188
|
-
- [type-newtype-ids](./type-newtype-ids.md) - ID types
|
|
@@ -1,143 +0,0 @@
|
|
|
1
|
-
# type-repr-transparent
|
|
2
|
-
|
|
3
|
-
> Use `#[repr(transparent)]` for newtypes in FFI contexts
|
|
4
|
-
|
|
5
|
-
## Why It Matters
|
|
6
|
-
|
|
7
|
-
`#[repr(transparent)]` guarantees a newtype has the same memory layout as its inner type. This is essential for FFI where you need type safety in Rust but must match C ABI layouts. Without it, the compiler may add padding or change layout.
|
|
8
|
-
|
|
9
|
-
## Bad
|
|
10
|
-
|
|
11
|
-
```rust
|
|
12
|
-
// No layout guarantee - might not match inner type in FFI
|
|
13
|
-
struct Handle(u64);
|
|
14
|
-
|
|
15
|
-
// Passing to C code might fail
|
|
16
|
-
extern "C" {
|
|
17
|
-
fn process_handle(h: Handle); // May not work correctly
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
// Wrapping C type without layout guarantee
|
|
21
|
-
struct SafePointer(*mut c_void);
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
## Good
|
|
25
|
-
|
|
26
|
-
```rust
|
|
27
|
-
// Guaranteed same layout as inner type
|
|
28
|
-
#[repr(transparent)]
|
|
29
|
-
struct Handle(u64);
|
|
30
|
-
|
|
31
|
-
// Safe for FFI
|
|
32
|
-
extern "C" {
|
|
33
|
-
fn process_handle(h: Handle); // Works - same layout as u64
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// FFI pointer wrapper
|
|
37
|
-
#[repr(transparent)]
|
|
38
|
-
struct SafePointer(*mut c_void);
|
|
39
|
-
|
|
40
|
-
impl SafePointer {
|
|
41
|
-
// Safe Rust API around raw pointer
|
|
42
|
-
pub fn new(ptr: *mut c_void) -> Option<Self> {
|
|
43
|
-
if ptr.is_null() {
|
|
44
|
-
None
|
|
45
|
-
} else {
|
|
46
|
-
Some(SafePointer(ptr))
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
## What repr(transparent) Guarantees
|
|
53
|
-
|
|
54
|
-
```rust
|
|
55
|
-
use std::mem::{size_of, align_of};
|
|
56
|
-
|
|
57
|
-
#[repr(transparent)]
|
|
58
|
-
struct Meters(f64);
|
|
59
|
-
|
|
60
|
-
// Same size
|
|
61
|
-
assert_eq!(size_of::<Meters>(), size_of::<f64>());
|
|
62
|
-
|
|
63
|
-
// Same alignment
|
|
64
|
-
assert_eq!(align_of::<Meters>(), align_of::<f64>());
|
|
65
|
-
|
|
66
|
-
// Same ABI - can pass where f64 expected
|
|
67
|
-
extern "C" fn measure(distance: Meters) { ... }
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
## With PhantomData
|
|
71
|
-
|
|
72
|
-
```rust
|
|
73
|
-
use std::marker::PhantomData;
|
|
74
|
-
|
|
75
|
-
// PhantomData is zero-sized, doesn't affect layout
|
|
76
|
-
#[repr(transparent)]
|
|
77
|
-
struct TypedHandle<T> {
|
|
78
|
-
raw: u64,
|
|
79
|
-
_marker: PhantomData<T>, // Zero-sized, ignored for layout
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// Still same layout as u64
|
|
83
|
-
assert_eq!(size_of::<TypedHandle<String>>(), size_of::<u64>());
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
## NonZero Wrappers
|
|
87
|
-
|
|
88
|
-
```rust
|
|
89
|
-
use std::num::NonZeroU64;
|
|
90
|
-
|
|
91
|
-
#[repr(transparent)]
|
|
92
|
-
struct NonZeroHandle(NonZeroU64);
|
|
93
|
-
|
|
94
|
-
// Inherits null-pointer optimization
|
|
95
|
-
assert_eq!(size_of::<Option<NonZeroHandle>>(), size_of::<u64>());
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
## FFI Pattern
|
|
99
|
-
|
|
100
|
-
```rust
|
|
101
|
-
mod ffi {
|
|
102
|
-
use std::os::raw::c_int;
|
|
103
|
-
|
|
104
|
-
#[repr(transparent)]
|
|
105
|
-
pub struct FileDescriptor(c_int);
|
|
106
|
-
|
|
107
|
-
extern "C" {
|
|
108
|
-
pub fn open(path: *const i8, flags: c_int) -> FileDescriptor;
|
|
109
|
-
pub fn close(fd: FileDescriptor) -> c_int;
|
|
110
|
-
pub fn read(fd: FileDescriptor, buf: *mut u8, len: usize) -> isize;
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
// Safe wrapper
|
|
115
|
-
pub struct File {
|
|
116
|
-
fd: ffi::FileDescriptor,
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
impl File {
|
|
120
|
-
pub fn open(path: &str) -> std::io::Result<Self> {
|
|
121
|
-
let c_path = std::ffi::CString::new(path)?;
|
|
122
|
-
let fd = unsafe { ffi::open(c_path.as_ptr(), 0) };
|
|
123
|
-
// ... error handling
|
|
124
|
-
Ok(File { fd })
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
## When to Use
|
|
130
|
-
|
|
131
|
-
| Scenario | Use `#[repr(transparent)]`? |
|
|
132
|
-
|----------|----------------------------|
|
|
133
|
-
| FFI newtype wrappers | Yes |
|
|
134
|
-
| Type-safe handles | Yes |
|
|
135
|
-
| NonZero optimization | Yes |
|
|
136
|
-
| Pure Rust newtypes | Optional (doesn't hurt) |
|
|
137
|
-
| Multi-field structs | N/A (only for single-field) |
|
|
138
|
-
|
|
139
|
-
## See Also
|
|
140
|
-
|
|
141
|
-
- [type-newtype-ids](./type-newtype-ids.md) - Newtype pattern
|
|
142
|
-
- [type-phantom-marker](./type-phantom-marker.md) - PhantomData usage
|
|
143
|
-
- [api-newtype-safety](./api-newtype-safety.md) - Type-safe newtypes
|
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
# type-result-fallible
|
|
2
|
-
|
|
3
|
-
> Use `Result<T, E>` for operations that can fail
|
|
4
|
-
|
|
5
|
-
## Why It Matters
|
|
6
|
-
|
|
7
|
-
`Result<T, E>` makes failure explicit in the type system. Callers must acknowledge and handle potential errors—they can't accidentally ignore failures. The `?` operator makes error propagation ergonomic while maintaining explicit error handling.
|
|
8
|
-
|
|
9
|
-
## Bad
|
|
10
|
-
|
|
11
|
-
```rust
|
|
12
|
-
// Returning Option loses error context
|
|
13
|
-
fn read_config(path: &str) -> Option<Config> {
|
|
14
|
-
let content = std::fs::read_to_string(path).ok()?; // Why did it fail?
|
|
15
|
-
toml::from_str(&content).ok() // Parse error lost
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
// Panicking on errors
|
|
19
|
-
fn read_config(path: &str) -> Config {
|
|
20
|
-
let content = std::fs::read_to_string(path).unwrap(); // Crashes
|
|
21
|
-
toml::from_str(&content).unwrap() // Crashes
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
// Sentinel values
|
|
25
|
-
fn divide(a: i32, b: i32) -> i32 {
|
|
26
|
-
if b == 0 { return -1; } // Magic value, easy to miss
|
|
27
|
-
a / b
|
|
28
|
-
}
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
## Good
|
|
32
|
-
|
|
33
|
-
```rust
|
|
34
|
-
// Result with clear error type
|
|
35
|
-
fn read_config(path: &str) -> Result<Config, ConfigError> {
|
|
36
|
-
let content = std::fs::read_to_string(path)
|
|
37
|
-
.map_err(ConfigError::IoError)?;
|
|
38
|
-
toml::from_str(&content)
|
|
39
|
-
.map_err(ConfigError::ParseError)
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
fn divide(a: i32, b: i32) -> Result<i32, DivisionError> {
|
|
43
|
-
if b == 0 {
|
|
44
|
-
return Err(DivisionError::DivideByZero);
|
|
45
|
-
}
|
|
46
|
-
Ok(a / b)
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// Caller must handle
|
|
50
|
-
match divide(10, 0) {
|
|
51
|
-
Ok(result) => println!("Result: {}", result),
|
|
52
|
-
Err(e) => println!("Error: {}", e),
|
|
53
|
-
}
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
## The ? Operator
|
|
57
|
-
|
|
58
|
-
```rust
|
|
59
|
-
fn process_file(path: &str) -> Result<ProcessedData, Error> {
|
|
60
|
-
let content = std::fs::read_to_string(path)?; // Propagates Err
|
|
61
|
-
let parsed: RawData = serde_json::from_str(&content)?;
|
|
62
|
-
let validated = validate(parsed)?;
|
|
63
|
-
let processed = transform(validated)?;
|
|
64
|
-
Ok(processed)
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// Equivalent to:
|
|
68
|
-
fn process_file(path: &str) -> Result<ProcessedData, Error> {
|
|
69
|
-
let content = match std::fs::read_to_string(path) {
|
|
70
|
-
Ok(c) => c,
|
|
71
|
-
Err(e) => return Err(e.into()),
|
|
72
|
-
};
|
|
73
|
-
// ... etc
|
|
74
|
-
}
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
## Result Combinators
|
|
78
|
-
|
|
79
|
-
```rust
|
|
80
|
-
let result: Result<i32, Error> = Ok(42);
|
|
81
|
-
|
|
82
|
-
// map: transform success value
|
|
83
|
-
let doubled = result.map(|n| n * 2); // Ok(84)
|
|
84
|
-
|
|
85
|
-
// map_err: transform error
|
|
86
|
-
let with_context = result.map_err(|e| format!("Failed: {}", e));
|
|
87
|
-
|
|
88
|
-
// and_then: chain fallible operations
|
|
89
|
-
let processed = result.and_then(|n| {
|
|
90
|
-
if n > 0 { Ok(n * 2) } else { Err(Error::Negative) }
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
// unwrap_or: provide default on error
|
|
94
|
-
let value = result.unwrap_or(0);
|
|
95
|
-
|
|
96
|
-
// ok(): convert to Option, discarding error
|
|
97
|
-
let maybe_value: Option<i32> = result.ok();
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
## Defining Error Types
|
|
101
|
-
|
|
102
|
-
```rust
|
|
103
|
-
use thiserror::Error;
|
|
104
|
-
|
|
105
|
-
#[derive(Error, Debug)]
|
|
106
|
-
pub enum ConfigError {
|
|
107
|
-
#[error("failed to read file: {0}")]
|
|
108
|
-
Io(#[from] std::io::Error),
|
|
109
|
-
|
|
110
|
-
#[error("failed to parse config: {0}")]
|
|
111
|
-
Parse(#[from] toml::de::Error),
|
|
112
|
-
|
|
113
|
-
#[error("missing required field: {0}")]
|
|
114
|
-
MissingField(String),
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
fn load_config(path: &str) -> Result<Config, ConfigError> {
|
|
118
|
-
let content = std::fs::read_to_string(path)?; // Io error
|
|
119
|
-
let config: Config = toml::from_str(&content)?; // Parse error
|
|
120
|
-
if config.name.is_empty() {
|
|
121
|
-
return Err(ConfigError::MissingField("name".into()));
|
|
122
|
-
}
|
|
123
|
-
Ok(config)
|
|
124
|
-
}
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
## See Also
|
|
128
|
-
|
|
129
|
-
- [err-thiserror-lib](./err-thiserror-lib.md) - Defining error types
|
|
130
|
-
- [err-question-mark](./err-question-mark.md) - Using ? operator
|
|
131
|
-
- [type-option-nullable](./type-option-nullable.md) - Option vs Result
|