agy-superpowers 5.2.2 → 5.2.4
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/CLAUDE.md +80 -0
- package/template/agent/rules/code-styles.md +31 -32
- package/template/agent/rules/debug-confirmation-policy.md +2 -0
- package/template/agent/rules/file-length-policy.md +2 -0
- package/template/agent/rules/git-policy.md +7 -0
- package/template/agent/rules/language-matching.md +2 -0
- package/template/agent/rules/scratch-scripts.md +39 -0
- package/template/agent/rules/superpowers.md +8 -51
- package/template/agent/skills/executing-plans/SKILL.md +17 -0
- package/template/agent/skills/systematic-debugging/SKILL.md +16 -0
- package/template/agent/skills/test-driven-development/SKILL.md +16 -0
- package/template/agent/skills/verification-before-completion/SKILL.md +22 -0
- package/template/agent/skills/writing-plans/SKILL.md +16 -0
- package/template/agent/skills/ai-integrated-product/SKILL.md +0 -57
- package/template/agent/skills/analytics-setup/SKILL.md +0 -51
- package/template/agent/skills/api-design/SKILL.md +0 -193
- package/template/agent/skills/app-store-optimizer/SKILL.md +0 -127
- package/template/agent/skills/auth-and-identity/SKILL.md +0 -167
- package/template/agent/skills/backend-developer/SKILL.md +0 -148
- package/template/agent/skills/bootstrapper-finance/SKILL.md +0 -55
- package/template/agent/skills/chrome-extension-developer/SKILL.md +0 -53
- package/template/agent/skills/community-manager/SKILL.md +0 -115
- package/template/agent/skills/content-marketer/SKILL.md +0 -111
- package/template/agent/skills/conversion-optimizer/SKILL.md +0 -142
- package/template/agent/skills/cto-architect/SKILL.md +0 -133
- package/template/agent/skills/customer-success-manager/SKILL.md +0 -126
- package/template/agent/skills/data-analyst/SKILL.md +0 -147
- package/template/agent/skills/devops-engineer/SKILL.md +0 -117
- package/template/agent/skills/email-infrastructure/SKILL.md +0 -164
- package/template/agent/skills/game-design/SKILL.md +0 -194
- package/template/agent/skills/game-developer/SKILL.md +0 -175
- package/template/agent/skills/growth-hacker/SKILL.md +0 -122
- package/template/agent/skills/idea-validator/SKILL.md +0 -55
- package/template/agent/skills/indie-legal/SKILL.md +0 -53
- package/template/agent/skills/influencer-marketer/SKILL.md +0 -141
- package/template/agent/skills/landing-page-builder/SKILL.md +0 -59
- package/template/agent/skills/launch-strategist/SKILL.md +0 -62
- package/template/agent/skills/market-researcher/SKILL.md +0 -53
- package/template/agent/skills/micro-saas-builder/SKILL.md +0 -56
- package/template/agent/skills/monetization-strategist/SKILL.md +0 -119
- package/template/agent/skills/paid-acquisition-specialist/SKILL.md +0 -119
- package/template/agent/skills/pricing-psychologist/SKILL.md +0 -58
- package/template/agent/skills/real-time-features/SKILL.md +0 -194
- package/template/agent/skills/retention-specialist/SKILL.md +0 -123
- package/template/agent/skills/rust-developer/SKILL.md +0 -281
- package/template/agent/skills/rust-developer/references/rust-rules/_sections.md +0 -231
- package/template/agent/skills/rust-developer/references/rust-rules/anti-clone-excessive.md +0 -124
- package/template/agent/skills/rust-developer/references/rust-rules/anti-collect-intermediate.md +0 -131
- package/template/agent/skills/rust-developer/references/rust-rules/anti-empty-catch.md +0 -132
- package/template/agent/skills/rust-developer/references/rust-rules/anti-expect-lazy.md +0 -95
- package/template/agent/skills/rust-developer/references/rust-rules/anti-format-hot-path.md +0 -141
- package/template/agent/skills/rust-developer/references/rust-rules/anti-index-over-iter.md +0 -125
- package/template/agent/skills/rust-developer/references/rust-rules/anti-lock-across-await.md +0 -127
- package/template/agent/skills/rust-developer/references/rust-rules/anti-over-abstraction.md +0 -120
- package/template/agent/skills/rust-developer/references/rust-rules/anti-panic-expected.md +0 -131
- package/template/agent/skills/rust-developer/references/rust-rules/anti-premature-optimize.md +0 -156
- package/template/agent/skills/rust-developer/references/rust-rules/anti-string-for-str.md +0 -122
- package/template/agent/skills/rust-developer/references/rust-rules/anti-stringly-typed.md +0 -167
- package/template/agent/skills/rust-developer/references/rust-rules/anti-type-erasure.md +0 -134
- package/template/agent/skills/rust-developer/references/rust-rules/anti-unwrap-abuse.md +0 -143
- package/template/agent/skills/rust-developer/references/rust-rules/anti-vec-for-slice.md +0 -121
- package/template/agent/skills/rust-developer/references/rust-rules/api-builder-must-use.md +0 -143
- package/template/agent/skills/rust-developer/references/rust-rules/api-builder-pattern.md +0 -187
- package/template/agent/skills/rust-developer/references/rust-rules/api-common-traits.md +0 -165
- package/template/agent/skills/rust-developer/references/rust-rules/api-default-impl.md +0 -177
- package/template/agent/skills/rust-developer/references/rust-rules/api-extension-trait.md +0 -163
- package/template/agent/skills/rust-developer/references/rust-rules/api-from-not-into.md +0 -146
- package/template/agent/skills/rust-developer/references/rust-rules/api-impl-asref.md +0 -142
- package/template/agent/skills/rust-developer/references/rust-rules/api-impl-into.md +0 -160
- package/template/agent/skills/rust-developer/references/rust-rules/api-must-use.md +0 -125
- package/template/agent/skills/rust-developer/references/rust-rules/api-newtype-safety.md +0 -162
- package/template/agent/skills/rust-developer/references/rust-rules/api-non-exhaustive.md +0 -177
- package/template/agent/skills/rust-developer/references/rust-rules/api-parse-dont-validate.md +0 -184
- package/template/agent/skills/rust-developer/references/rust-rules/api-sealed-trait.md +0 -168
- package/template/agent/skills/rust-developer/references/rust-rules/api-serde-optional.md +0 -182
- package/template/agent/skills/rust-developer/references/rust-rules/api-typestate.md +0 -199
- package/template/agent/skills/rust-developer/references/rust-rules/async-bounded-channel.md +0 -175
- package/template/agent/skills/rust-developer/references/rust-rules/async-broadcast-pubsub.md +0 -185
- package/template/agent/skills/rust-developer/references/rust-rules/async-cancellation-token.md +0 -203
- package/template/agent/skills/rust-developer/references/rust-rules/async-clone-before-await.md +0 -171
- package/template/agent/skills/rust-developer/references/rust-rules/async-join-parallel.md +0 -158
- package/template/agent/skills/rust-developer/references/rust-rules/async-joinset-structured.md +0 -195
- package/template/agent/skills/rust-developer/references/rust-rules/async-mpsc-queue.md +0 -171
- package/template/agent/skills/rust-developer/references/rust-rules/async-no-lock-await.md +0 -156
- package/template/agent/skills/rust-developer/references/rust-rules/async-oneshot-response.md +0 -191
- package/template/agent/skills/rust-developer/references/rust-rules/async-select-racing.md +0 -198
- package/template/agent/skills/rust-developer/references/rust-rules/async-spawn-blocking.md +0 -154
- package/template/agent/skills/rust-developer/references/rust-rules/async-tokio-fs.md +0 -167
- package/template/agent/skills/rust-developer/references/rust-rules/async-tokio-runtime.md +0 -169
- package/template/agent/skills/rust-developer/references/rust-rules/async-try-join.md +0 -172
- package/template/agent/skills/rust-developer/references/rust-rules/async-watch-latest.md +0 -189
- package/template/agent/skills/rust-developer/references/rust-rules/doc-all-public.md +0 -113
- package/template/agent/skills/rust-developer/references/rust-rules/doc-cargo-metadata.md +0 -147
- package/template/agent/skills/rust-developer/references/rust-rules/doc-errors-section.md +0 -122
- package/template/agent/skills/rust-developer/references/rust-rules/doc-examples-section.md +0 -161
- package/template/agent/skills/rust-developer/references/rust-rules/doc-hidden-setup.md +0 -149
- package/template/agent/skills/rust-developer/references/rust-rules/doc-intra-links.md +0 -138
- package/template/agent/skills/rust-developer/references/rust-rules/doc-link-types.md +0 -169
- package/template/agent/skills/rust-developer/references/rust-rules/doc-module-inner.md +0 -116
- package/template/agent/skills/rust-developer/references/rust-rules/doc-panics-section.md +0 -128
- package/template/agent/skills/rust-developer/references/rust-rules/doc-question-mark.md +0 -136
- package/template/agent/skills/rust-developer/references/rust-rules/doc-safety-section.md +0 -131
- package/template/agent/skills/rust-developer/references/rust-rules/err-anyhow-app.md +0 -179
- package/template/agent/skills/rust-developer/references/rust-rules/err-context-chain.md +0 -144
- package/template/agent/skills/rust-developer/references/rust-rules/err-custom-type.md +0 -152
- package/template/agent/skills/rust-developer/references/rust-rules/err-doc-errors.md +0 -145
- package/template/agent/skills/rust-developer/references/rust-rules/err-expect-bugs-only.md +0 -133
- package/template/agent/skills/rust-developer/references/rust-rules/err-from-impl.md +0 -152
- package/template/agent/skills/rust-developer/references/rust-rules/err-lowercase-msg.md +0 -124
- package/template/agent/skills/rust-developer/references/rust-rules/err-no-unwrap-prod.md +0 -115
- package/template/agent/skills/rust-developer/references/rust-rules/err-question-mark.md +0 -151
- package/template/agent/skills/rust-developer/references/rust-rules/err-result-over-panic.md +0 -130
- package/template/agent/skills/rust-developer/references/rust-rules/err-source-chain.md +0 -155
- package/template/agent/skills/rust-developer/references/rust-rules/err-thiserror-lib.md +0 -171
- package/template/agent/skills/rust-developer/references/rust-rules/lint-cargo-metadata.md +0 -138
- package/template/agent/skills/rust-developer/references/rust-rules/lint-deny-correctness.md +0 -107
- package/template/agent/skills/rust-developer/references/rust-rules/lint-missing-docs.md +0 -154
- package/template/agent/skills/rust-developer/references/rust-rules/lint-pedantic-selective.md +0 -118
- package/template/agent/skills/rust-developer/references/rust-rules/lint-rustfmt-check.md +0 -157
- package/template/agent/skills/rust-developer/references/rust-rules/lint-unsafe-doc.md +0 -133
- package/template/agent/skills/rust-developer/references/rust-rules/lint-warn-complexity.md +0 -131
- package/template/agent/skills/rust-developer/references/rust-rules/lint-warn-perf.md +0 -136
- package/template/agent/skills/rust-developer/references/rust-rules/lint-warn-style.md +0 -135
- package/template/agent/skills/rust-developer/references/rust-rules/lint-warn-suspicious.md +0 -122
- package/template/agent/skills/rust-developer/references/rust-rules/lint-workspace-lints.md +0 -172
- package/template/agent/skills/rust-developer/references/rust-rules/mem-arena-allocator.md +0 -168
- package/template/agent/skills/rust-developer/references/rust-rules/mem-arrayvec.md +0 -142
- package/template/agent/skills/rust-developer/references/rust-rules/mem-assert-type-size.md +0 -168
- package/template/agent/skills/rust-developer/references/rust-rules/mem-avoid-format.md +0 -147
- package/template/agent/skills/rust-developer/references/rust-rules/mem-box-large-variant.md +0 -158
- package/template/agent/skills/rust-developer/references/rust-rules/mem-boxed-slice.md +0 -139
- package/template/agent/skills/rust-developer/references/rust-rules/mem-clone-from.md +0 -147
- package/template/agent/skills/rust-developer/references/rust-rules/mem-compact-string.md +0 -149
- package/template/agent/skills/rust-developer/references/rust-rules/mem-reuse-collections.md +0 -174
- package/template/agent/skills/rust-developer/references/rust-rules/mem-smaller-integers.md +0 -159
- package/template/agent/skills/rust-developer/references/rust-rules/mem-smallvec.md +0 -138
- package/template/agent/skills/rust-developer/references/rust-rules/mem-thinvec.md +0 -142
- package/template/agent/skills/rust-developer/references/rust-rules/mem-with-capacity.md +0 -156
- package/template/agent/skills/rust-developer/references/rust-rules/mem-write-over-format.md +0 -172
- package/template/agent/skills/rust-developer/references/rust-rules/mem-zero-copy.md +0 -164
- package/template/agent/skills/rust-developer/references/rust-rules/name-acronym-word.md +0 -99
- package/template/agent/skills/rust-developer/references/rust-rules/name-as-free.md +0 -104
- package/template/agent/skills/rust-developer/references/rust-rules/name-consts-screaming.md +0 -94
- package/template/agent/skills/rust-developer/references/rust-rules/name-crate-no-rs.md +0 -78
- package/template/agent/skills/rust-developer/references/rust-rules/name-funcs-snake.md +0 -76
- package/template/agent/skills/rust-developer/references/rust-rules/name-into-ownership.md +0 -123
- package/template/agent/skills/rust-developer/references/rust-rules/name-is-has-bool.md +0 -127
- package/template/agent/skills/rust-developer/references/rust-rules/name-iter-convention.md +0 -129
- package/template/agent/skills/rust-developer/references/rust-rules/name-iter-method.md +0 -131
- package/template/agent/skills/rust-developer/references/rust-rules/name-iter-type-match.md +0 -142
- package/template/agent/skills/rust-developer/references/rust-rules/name-lifetime-short.md +0 -86
- package/template/agent/skills/rust-developer/references/rust-rules/name-no-get-prefix.md +0 -154
- package/template/agent/skills/rust-developer/references/rust-rules/name-to-expensive.md +0 -118
- package/template/agent/skills/rust-developer/references/rust-rules/name-type-param-single.md +0 -92
- package/template/agent/skills/rust-developer/references/rust-rules/name-types-camel.md +0 -65
- package/template/agent/skills/rust-developer/references/rust-rules/name-variants-camel.md +0 -101
- package/template/agent/skills/rust-developer/references/rust-rules/opt-bounds-check.md +0 -161
- package/template/agent/skills/rust-developer/references/rust-rules/opt-cache-friendly.md +0 -187
- package/template/agent/skills/rust-developer/references/rust-rules/opt-codegen-units.md +0 -142
- package/template/agent/skills/rust-developer/references/rust-rules/opt-cold-unlikely.md +0 -152
- package/template/agent/skills/rust-developer/references/rust-rules/opt-inline-always-rare.md +0 -141
- package/template/agent/skills/rust-developer/references/rust-rules/opt-inline-never-cold.md +0 -181
- package/template/agent/skills/rust-developer/references/rust-rules/opt-inline-small.md +0 -160
- package/template/agent/skills/rust-developer/references/rust-rules/opt-likely-hint.md +0 -171
- package/template/agent/skills/rust-developer/references/rust-rules/opt-lto-release.md +0 -130
- package/template/agent/skills/rust-developer/references/rust-rules/opt-pgo-profile.md +0 -167
- package/template/agent/skills/rust-developer/references/rust-rules/opt-simd-portable.md +0 -144
- package/template/agent/skills/rust-developer/references/rust-rules/opt-target-cpu.md +0 -154
- package/template/agent/skills/rust-developer/references/rust-rules/own-arc-shared.md +0 -141
- package/template/agent/skills/rust-developer/references/rust-rules/own-borrow-over-clone.md +0 -95
- package/template/agent/skills/rust-developer/references/rust-rules/own-clone-explicit.md +0 -135
- package/template/agent/skills/rust-developer/references/rust-rules/own-copy-small.md +0 -124
- package/template/agent/skills/rust-developer/references/rust-rules/own-cow-conditional.md +0 -135
- package/template/agent/skills/rust-developer/references/rust-rules/own-lifetime-elision.md +0 -134
- package/template/agent/skills/rust-developer/references/rust-rules/own-move-large.md +0 -134
- package/template/agent/skills/rust-developer/references/rust-rules/own-mutex-interior.md +0 -105
- package/template/agent/skills/rust-developer/references/rust-rules/own-rc-single-thread.md +0 -65
- package/template/agent/skills/rust-developer/references/rust-rules/own-refcell-interior.md +0 -97
- package/template/agent/skills/rust-developer/references/rust-rules/own-rwlock-readers.md +0 -122
- package/template/agent/skills/rust-developer/references/rust-rules/own-slice-over-vec.md +0 -119
- package/template/agent/skills/rust-developer/references/rust-rules/perf-black-box-bench.md +0 -153
- package/template/agent/skills/rust-developer/references/rust-rules/perf-chain-avoid.md +0 -136
- package/template/agent/skills/rust-developer/references/rust-rules/perf-collect-into.md +0 -133
- package/template/agent/skills/rust-developer/references/rust-rules/perf-collect-once.md +0 -120
- package/template/agent/skills/rust-developer/references/rust-rules/perf-drain-reuse.md +0 -137
- package/template/agent/skills/rust-developer/references/rust-rules/perf-entry-api.md +0 -134
- package/template/agent/skills/rust-developer/references/rust-rules/perf-extend-batch.md +0 -150
- package/template/agent/skills/rust-developer/references/rust-rules/perf-iter-lazy.md +0 -123
- package/template/agent/skills/rust-developer/references/rust-rules/perf-iter-over-index.md +0 -113
- package/template/agent/skills/rust-developer/references/rust-rules/perf-profile-first.md +0 -175
- package/template/agent/skills/rust-developer/references/rust-rules/perf-release-profile.md +0 -149
- package/template/agent/skills/rust-developer/references/rust-rules/proj-bin-dir.md +0 -142
- package/template/agent/skills/rust-developer/references/rust-rules/proj-flat-small.md +0 -133
- package/template/agent/skills/rust-developer/references/rust-rules/proj-lib-main-split.md +0 -148
- package/template/agent/skills/rust-developer/references/rust-rules/proj-mod-by-feature.md +0 -130
- package/template/agent/skills/rust-developer/references/rust-rules/proj-mod-rs-dir.md +0 -120
- package/template/agent/skills/rust-developer/references/rust-rules/proj-prelude-module.md +0 -155
- package/template/agent/skills/rust-developer/references/rust-rules/proj-pub-crate-internal.md +0 -139
- package/template/agent/skills/rust-developer/references/rust-rules/proj-pub-super-parent.md +0 -135
- package/template/agent/skills/rust-developer/references/rust-rules/proj-pub-use-reexport.md +0 -162
- package/template/agent/skills/rust-developer/references/rust-rules/proj-workspace-deps.md +0 -186
- package/template/agent/skills/rust-developer/references/rust-rules/proj-workspace-large.md +0 -162
- package/template/agent/skills/rust-developer/references/rust-rules/test-arrange-act-assert.md +0 -160
- package/template/agent/skills/rust-developer/references/rust-rules/test-cfg-test-module.md +0 -151
- package/template/agent/skills/rust-developer/references/rust-rules/test-criterion-bench.md +0 -171
- package/template/agent/skills/rust-developer/references/rust-rules/test-descriptive-names.md +0 -142
- package/template/agent/skills/rust-developer/references/rust-rules/test-doctest-examples.md +0 -168
- package/template/agent/skills/rust-developer/references/rust-rules/test-fixture-raii.md +0 -151
- package/template/agent/skills/rust-developer/references/rust-rules/test-integration-dir.md +0 -144
- package/template/agent/skills/rust-developer/references/rust-rules/test-mock-traits.md +0 -189
- package/template/agent/skills/rust-developer/references/rust-rules/test-mockall-mocking.md +0 -226
- package/template/agent/skills/rust-developer/references/rust-rules/test-proptest-properties.md +0 -161
- package/template/agent/skills/rust-developer/references/rust-rules/test-should-panic.md +0 -130
- package/template/agent/skills/rust-developer/references/rust-rules/test-tokio-async.md +0 -154
- package/template/agent/skills/rust-developer/references/rust-rules/test-use-super.md +0 -127
- package/template/agent/skills/rust-developer/references/rust-rules/type-enum-states.md +0 -154
- package/template/agent/skills/rust-developer/references/rust-rules/type-generic-bounds.md +0 -142
- package/template/agent/skills/rust-developer/references/rust-rules/type-never-diverge.md +0 -146
- package/template/agent/skills/rust-developer/references/rust-rules/type-newtype-ids.md +0 -160
- package/template/agent/skills/rust-developer/references/rust-rules/type-newtype-validated.md +0 -159
- package/template/agent/skills/rust-developer/references/rust-rules/type-no-stringly.md +0 -144
- package/template/agent/skills/rust-developer/references/rust-rules/type-option-nullable.md +0 -137
- package/template/agent/skills/rust-developer/references/rust-rules/type-phantom-marker.md +0 -188
- package/template/agent/skills/rust-developer/references/rust-rules/type-repr-transparent.md +0 -143
- package/template/agent/skills/rust-developer/references/rust-rules/type-result-fallible.md +0 -131
- package/template/agent/skills/saas-architect/SKILL.md +0 -139
- package/template/agent/skills/security-engineer/SKILL.md +0 -133
- package/template/agent/skills/seo-specialist/SKILL.md +0 -130
- package/template/agent/skills/solo-founder-ops/SKILL.md +0 -56
|
@@ -1,182 +0,0 @@
|
|
|
1
|
-
# api-serde-optional
|
|
2
|
-
|
|
3
|
-
> Make serde a feature flag, not a hard dependency for library crates
|
|
4
|
-
|
|
5
|
-
## Why It Matters
|
|
6
|
-
|
|
7
|
-
Not all users of your library need serialization. Making serde a required dependency adds compile time and binary size for everyone. Feature flags let users opt-in to serde support only when needed, following Rust's philosophy of zero-cost abstractions and minimal dependencies.
|
|
8
|
-
|
|
9
|
-
## Bad
|
|
10
|
-
|
|
11
|
-
```rust
|
|
12
|
-
// Cargo.toml
|
|
13
|
-
[dependencies]
|
|
14
|
-
serde = { version = "1.0", features = ["derive"] }
|
|
15
|
-
|
|
16
|
-
// lib.rs
|
|
17
|
-
use serde::{Serialize, Deserialize};
|
|
18
|
-
|
|
19
|
-
// Every user pays for serde, even if they don't need it
|
|
20
|
-
#[derive(Serialize, Deserialize)]
|
|
21
|
-
pub struct Config {
|
|
22
|
-
pub name: String,
|
|
23
|
-
pub value: i32,
|
|
24
|
-
}
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
## Good
|
|
28
|
-
|
|
29
|
-
```rust
|
|
30
|
-
// Cargo.toml
|
|
31
|
-
[dependencies]
|
|
32
|
-
serde = { version = "1.0", features = ["derive"], optional = true }
|
|
33
|
-
|
|
34
|
-
[features]
|
|
35
|
-
default = []
|
|
36
|
-
serde = ["dep:serde"]
|
|
37
|
-
|
|
38
|
-
// lib.rs
|
|
39
|
-
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
|
40
|
-
pub struct Config {
|
|
41
|
-
pub name: String,
|
|
42
|
-
pub value: i32,
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// Users opt-in:
|
|
46
|
-
// my_crate = { version = "1.0", features = ["serde"] }
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
## Macro Pattern
|
|
50
|
-
|
|
51
|
-
```rust
|
|
52
|
-
// Reusable macro for serde derives
|
|
53
|
-
#[cfg(feature = "serde")]
|
|
54
|
-
macro_rules! impl_serde {
|
|
55
|
-
($($t:ty),*) => {
|
|
56
|
-
$(
|
|
57
|
-
impl serde::Serialize for $t {
|
|
58
|
-
// ...
|
|
59
|
-
}
|
|
60
|
-
impl<'de> serde::Deserialize<'de> for $t {
|
|
61
|
-
// ...
|
|
62
|
-
}
|
|
63
|
-
)*
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
#[cfg(not(feature = "serde"))]
|
|
68
|
-
macro_rules! impl_serde {
|
|
69
|
-
($($t:ty),*) => {};
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// Or use cfg_attr for derived impls
|
|
73
|
-
#[derive(Debug, Clone)]
|
|
74
|
-
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
|
75
|
-
pub struct Point {
|
|
76
|
-
pub x: f64,
|
|
77
|
-
pub y: f64,
|
|
78
|
-
}
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
## Feature Documentation
|
|
82
|
-
|
|
83
|
-
```rust
|
|
84
|
-
// lib.rs
|
|
85
|
-
|
|
86
|
-
//! # Features
|
|
87
|
-
//!
|
|
88
|
-
//! - `serde`: Enables `Serialize` and `Deserialize` implementations for all types.
|
|
89
|
-
//!
|
|
90
|
-
//! # Example with serde
|
|
91
|
-
//!
|
|
92
|
-
//! ```toml
|
|
93
|
-
//! [dependencies]
|
|
94
|
-
//! my_crate = { version = "1.0", features = ["serde"] }
|
|
95
|
-
//! ```
|
|
96
|
-
|
|
97
|
-
#![cfg_attr(docsrs, feature(doc_cfg))]
|
|
98
|
-
|
|
99
|
-
/// A configuration type.
|
|
100
|
-
///
|
|
101
|
-
/// When the `serde` feature is enabled, this type implements
|
|
102
|
-
/// `Serialize` and `Deserialize`.
|
|
103
|
-
#[derive(Debug, Clone)]
|
|
104
|
-
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
|
105
|
-
#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
|
|
106
|
-
pub struct Config {
|
|
107
|
-
pub name: String,
|
|
108
|
-
}
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
## Multiple Optional Dependencies
|
|
112
|
-
|
|
113
|
-
```rust
|
|
114
|
-
// Cargo.toml
|
|
115
|
-
[dependencies]
|
|
116
|
-
serde = { version = "1.0", features = ["derive"], optional = true }
|
|
117
|
-
rkyv = { version = "0.7", optional = true }
|
|
118
|
-
borsh = { version = "0.10", optional = true }
|
|
119
|
-
|
|
120
|
-
[features]
|
|
121
|
-
default = []
|
|
122
|
-
serde = ["dep:serde"]
|
|
123
|
-
rkyv = ["dep:rkyv"]
|
|
124
|
-
borsh = ["dep:borsh"]
|
|
125
|
-
|
|
126
|
-
// lib.rs
|
|
127
|
-
#[derive(Debug, Clone)]
|
|
128
|
-
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
|
129
|
-
#[cfg_attr(feature = "rkyv", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
|
|
130
|
-
#[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize, borsh::BorshDeserialize))]
|
|
131
|
-
pub struct Message {
|
|
132
|
-
pub id: u64,
|
|
133
|
-
pub content: String,
|
|
134
|
-
}
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
## Testing with Features
|
|
138
|
-
|
|
139
|
-
```bash
|
|
140
|
-
# Test without serde
|
|
141
|
-
cargo test
|
|
142
|
-
|
|
143
|
-
# Test with serde
|
|
144
|
-
cargo test --features serde
|
|
145
|
-
|
|
146
|
-
# Test all feature combinations
|
|
147
|
-
cargo test --all-features
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
```rust
|
|
151
|
-
// Test serde round-trip when feature enabled
|
|
152
|
-
#[cfg(feature = "serde")]
|
|
153
|
-
#[test]
|
|
154
|
-
fn test_serde_roundtrip() {
|
|
155
|
-
let config = Config { name: "test".into() };
|
|
156
|
-
let json = serde_json::to_string(&config).unwrap();
|
|
157
|
-
let parsed: Config = serde_json::from_str(&json).unwrap();
|
|
158
|
-
assert_eq!(config, parsed);
|
|
159
|
-
}
|
|
160
|
-
```
|
|
161
|
-
|
|
162
|
-
## When to Make Serde Required
|
|
163
|
-
|
|
164
|
-
```rust
|
|
165
|
-
// ✅ Required: Library is about serialization
|
|
166
|
-
// (e.g., json-schema, config-file parser)
|
|
167
|
-
[dependencies]
|
|
168
|
-
serde = "1.0"
|
|
169
|
-
|
|
170
|
-
// ✅ Required: Domain heavily uses serde
|
|
171
|
-
// (e.g., API client, data format library)
|
|
172
|
-
|
|
173
|
-
// ❌ Optional: General-purpose utility library
|
|
174
|
-
// ❌ Optional: Math/algorithm library
|
|
175
|
-
// ❌ Optional: Most libraries!
|
|
176
|
-
```
|
|
177
|
-
|
|
178
|
-
## See Also
|
|
179
|
-
|
|
180
|
-
- [proj-lib-main-split](./proj-lib-main-split.md) - Library structure
|
|
181
|
-
- [api-common-traits](./api-common-traits.md) - Core trait implementations
|
|
182
|
-
- [lint-deny-correctness](./lint-deny-correctness.md) - Feature testing
|
|
@@ -1,199 +0,0 @@
|
|
|
1
|
-
# api-typestate
|
|
2
|
-
|
|
3
|
-
> Use typestate pattern to encode state machine invariants in the type system
|
|
4
|
-
|
|
5
|
-
## Why It Matters
|
|
6
|
-
|
|
7
|
-
State machines with runtime state checks ("are we connected?", "is the transaction started?") can have invalid transitions. The typestate pattern uses different types for each state, making invalid state transitions compile errors. The compiler enforces your state machine.
|
|
8
|
-
|
|
9
|
-
## Bad
|
|
10
|
-
|
|
11
|
-
```rust
|
|
12
|
-
struct Connection {
|
|
13
|
-
state: ConnectionState,
|
|
14
|
-
socket: Option<TcpStream>,
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
enum ConnectionState {
|
|
18
|
-
Disconnected,
|
|
19
|
-
Connected,
|
|
20
|
-
Authenticated,
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
impl Connection {
|
|
24
|
-
fn send(&mut self, data: &[u8]) -> Result<(), Error> {
|
|
25
|
-
// Runtime check - can fail if called in wrong state
|
|
26
|
-
if self.state != ConnectionState::Authenticated {
|
|
27
|
-
return Err(Error::NotAuthenticated);
|
|
28
|
-
}
|
|
29
|
-
self.socket.as_mut().unwrap().write_all(data)?;
|
|
30
|
-
Ok(())
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
fn authenticate(&mut self, password: &str) -> Result<(), Error> {
|
|
34
|
-
// Runtime check - can fail
|
|
35
|
-
if self.state != ConnectionState::Connected {
|
|
36
|
-
return Err(Error::NotConnected);
|
|
37
|
-
}
|
|
38
|
-
// ...
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// Bug: forgot to authenticate
|
|
43
|
-
let mut conn = Connection::new();
|
|
44
|
-
conn.connect()?;
|
|
45
|
-
conn.send(b"data")?; // Runtime error: NotAuthenticated
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
## Good
|
|
49
|
-
|
|
50
|
-
```rust
|
|
51
|
-
// Different types for each state
|
|
52
|
-
struct Disconnected;
|
|
53
|
-
struct Connected { socket: TcpStream }
|
|
54
|
-
struct Authenticated { socket: TcpStream, session: Session }
|
|
55
|
-
|
|
56
|
-
struct Connection<State> {
|
|
57
|
-
state: State,
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
impl Connection<Disconnected> {
|
|
61
|
-
fn new() -> Self {
|
|
62
|
-
Connection { state: Disconnected }
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
fn connect(self, addr: &str) -> Result<Connection<Connected>, Error> {
|
|
66
|
-
let socket = TcpStream::connect(addr)?;
|
|
67
|
-
Ok(Connection { state: Connected { socket } })
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
impl Connection<Connected> {
|
|
72
|
-
fn authenticate(self, password: &str) -> Result<Connection<Authenticated>, Error> {
|
|
73
|
-
let session = do_auth(&self.state.socket, password)?;
|
|
74
|
-
Ok(Connection {
|
|
75
|
-
state: Authenticated { socket: self.state.socket, session }
|
|
76
|
-
})
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
impl Connection<Authenticated> {
|
|
81
|
-
fn send(&mut self, data: &[u8]) -> Result<(), Error> {
|
|
82
|
-
// No runtime check needed - type guarantees we're authenticated
|
|
83
|
-
self.state.socket.write_all(data)?;
|
|
84
|
-
Ok(())
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
// Bug: forgot to authenticate
|
|
89
|
-
let conn = Connection::new();
|
|
90
|
-
let conn = conn.connect("server:8080")?;
|
|
91
|
-
conn.send(b"data"); // Compile error! send() not available on Connection<Connected>
|
|
92
|
-
|
|
93
|
-
// Correct usage
|
|
94
|
-
let conn = Connection::new();
|
|
95
|
-
let conn = conn.connect("server:8080")?;
|
|
96
|
-
let mut conn = conn.authenticate("secret")?;
|
|
97
|
-
conn.send(b"data")?; // Works - type is Connection<Authenticated>
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
## Builder Typestate
|
|
101
|
-
|
|
102
|
-
```rust
|
|
103
|
-
// Enforce required fields via typestate
|
|
104
|
-
struct BuilderNoUrl;
|
|
105
|
-
struct BuilderWithUrl { url: String }
|
|
106
|
-
|
|
107
|
-
struct RequestBuilder<State> {
|
|
108
|
-
state: State,
|
|
109
|
-
timeout: Option<Duration>,
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
impl RequestBuilder<BuilderNoUrl> {
|
|
113
|
-
fn new() -> Self {
|
|
114
|
-
RequestBuilder {
|
|
115
|
-
state: BuilderNoUrl,
|
|
116
|
-
timeout: None,
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
fn url(self, url: &str) -> RequestBuilder<BuilderWithUrl> {
|
|
121
|
-
RequestBuilder {
|
|
122
|
-
state: BuilderWithUrl { url: url.to_string() },
|
|
123
|
-
timeout: self.timeout,
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
impl RequestBuilder<BuilderWithUrl> {
|
|
129
|
-
fn timeout(mut self, t: Duration) -> Self {
|
|
130
|
-
self.timeout = Some(t);
|
|
131
|
-
self
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// Only available once URL is set
|
|
135
|
-
fn build(self) -> Request {
|
|
136
|
-
Request {
|
|
137
|
-
url: self.state.url,
|
|
138
|
-
timeout: self.timeout,
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
// Compile error: build() not available
|
|
144
|
-
let bad = RequestBuilder::new().build();
|
|
145
|
-
|
|
146
|
-
// Correct: must set URL first
|
|
147
|
-
let good = RequestBuilder::new()
|
|
148
|
-
.url("https://example.com")
|
|
149
|
-
.timeout(Duration::from_secs(30))
|
|
150
|
-
.build();
|
|
151
|
-
```
|
|
152
|
-
|
|
153
|
-
## Transaction Example
|
|
154
|
-
|
|
155
|
-
```rust
|
|
156
|
-
struct NotStarted;
|
|
157
|
-
struct InProgress { tx_id: u64 }
|
|
158
|
-
struct Committed;
|
|
159
|
-
|
|
160
|
-
struct Transaction<State> {
|
|
161
|
-
conn: Connection,
|
|
162
|
-
state: State,
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
impl Transaction<NotStarted> {
|
|
166
|
-
fn begin(conn: Connection) -> Result<Transaction<InProgress>, Error> {
|
|
167
|
-
let tx_id = conn.execute("BEGIN")?;
|
|
168
|
-
Ok(Transaction {
|
|
169
|
-
conn,
|
|
170
|
-
state: InProgress { tx_id },
|
|
171
|
-
})
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
impl Transaction<InProgress> {
|
|
176
|
-
fn execute(&mut self, sql: &str) -> Result<(), Error> {
|
|
177
|
-
self.conn.execute(sql)
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
fn commit(self) -> Result<Transaction<Committed>, Error> {
|
|
181
|
-
self.conn.execute("COMMIT")?;
|
|
182
|
-
Ok(Transaction {
|
|
183
|
-
conn: self.conn,
|
|
184
|
-
state: Committed,
|
|
185
|
-
})
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
fn rollback(self) -> Connection {
|
|
189
|
-
let _ = self.conn.execute("ROLLBACK");
|
|
190
|
-
self.conn
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
```
|
|
194
|
-
|
|
195
|
-
## See Also
|
|
196
|
-
|
|
197
|
-
- [api-builder-pattern](./api-builder-pattern.md) - Basic builder pattern
|
|
198
|
-
- [api-parse-dont-validate](./api-parse-dont-validate.md) - Type-driven invariants
|
|
199
|
-
- [api-sealed-trait](./api-sealed-trait.md) - Restricting trait implementations
|
|
@@ -1,175 +0,0 @@
|
|
|
1
|
-
# async-bounded-channel
|
|
2
|
-
|
|
3
|
-
> Use bounded channels to apply backpressure and prevent unbounded memory growth
|
|
4
|
-
|
|
5
|
-
## Why It Matters
|
|
6
|
-
|
|
7
|
-
Unbounded channels grow without limit when producers outpace consumers. In production, this leads to memory exhaustion. Bounded channels apply backpressure—producers wait when the channel is full, naturally throttling the system. This prevents OOM and makes resource usage predictable.
|
|
8
|
-
|
|
9
|
-
## Bad
|
|
10
|
-
|
|
11
|
-
```rust
|
|
12
|
-
use tokio::sync::mpsc;
|
|
13
|
-
|
|
14
|
-
// Unbounded channel - can grow forever
|
|
15
|
-
let (tx, mut rx) = mpsc::unbounded_channel::<Message>();
|
|
16
|
-
|
|
17
|
-
// Fast producer, slow consumer = unbounded memory growth
|
|
18
|
-
tokio::spawn(async move {
|
|
19
|
-
loop {
|
|
20
|
-
let msg = generate_message();
|
|
21
|
-
tx.send(msg).unwrap(); // Never blocks, never fails (until OOM)
|
|
22
|
-
}
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
tokio::spawn(async move {
|
|
26
|
-
while let Some(msg) = rx.recv().await {
|
|
27
|
-
slow_process(msg).await; // Can't keep up
|
|
28
|
-
}
|
|
29
|
-
});
|
|
30
|
-
// Memory grows unboundedly until crash
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
## Good
|
|
34
|
-
|
|
35
|
-
```rust
|
|
36
|
-
use tokio::sync::mpsc;
|
|
37
|
-
|
|
38
|
-
// Bounded channel - backpressure when full
|
|
39
|
-
let (tx, mut rx) = mpsc::channel::<Message>(100); // Max 100 items
|
|
40
|
-
|
|
41
|
-
// Producer waits when channel full
|
|
42
|
-
tokio::spawn(async move {
|
|
43
|
-
loop {
|
|
44
|
-
let msg = generate_message();
|
|
45
|
-
// Blocks if channel is full - natural backpressure
|
|
46
|
-
tx.send(msg).await.unwrap();
|
|
47
|
-
}
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
tokio::spawn(async move {
|
|
51
|
-
while let Some(msg) = rx.recv().await {
|
|
52
|
-
slow_process(msg).await;
|
|
53
|
-
}
|
|
54
|
-
});
|
|
55
|
-
// Memory usage capped at ~100 messages
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
## Choosing Buffer Size
|
|
59
|
-
|
|
60
|
-
```rust
|
|
61
|
-
// Too small: frequent blocking, reduced throughput
|
|
62
|
-
let (tx, rx) = mpsc::channel::<Item>(1);
|
|
63
|
-
|
|
64
|
-
// Too large: delayed backpressure, memory waste
|
|
65
|
-
let (tx, rx) = mpsc::channel::<Item>(1_000_000);
|
|
66
|
-
|
|
67
|
-
// Guidelines:
|
|
68
|
-
// - Start with expected burst size
|
|
69
|
-
// - Measure actual usage in production
|
|
70
|
-
// - Err on the smaller side initially
|
|
71
|
-
|
|
72
|
-
// Small items, high throughput
|
|
73
|
-
let (tx, rx) = mpsc::channel::<u64>(1000);
|
|
74
|
-
|
|
75
|
-
// Large items, moderate throughput
|
|
76
|
-
let (tx, rx) = mpsc::channel::<LargeStruct>(100);
|
|
77
|
-
|
|
78
|
-
// Low latency requirement
|
|
79
|
-
let (tx, rx) = mpsc::channel::<Command>(10);
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
## Handling Full Channel
|
|
83
|
-
|
|
84
|
-
```rust
|
|
85
|
-
use tokio::sync::mpsc;
|
|
86
|
-
use tokio::time::{timeout, Duration};
|
|
87
|
-
|
|
88
|
-
let (tx, mut rx) = mpsc::channel::<Message>(100);
|
|
89
|
-
|
|
90
|
-
// Option 1: Wait indefinitely (default)
|
|
91
|
-
tx.send(msg).await?;
|
|
92
|
-
|
|
93
|
-
// Option 2: Try send, fail if full
|
|
94
|
-
match tx.try_send(msg) {
|
|
95
|
-
Ok(()) => println!("Sent"),
|
|
96
|
-
Err(TrySendError::Full(msg)) => {
|
|
97
|
-
println!("Channel full, dropping message");
|
|
98
|
-
}
|
|
99
|
-
Err(TrySendError::Closed(msg)) => {
|
|
100
|
-
println!("Receiver dropped");
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// Option 3: Timeout
|
|
105
|
-
match timeout(Duration::from_secs(1), tx.send(msg)).await {
|
|
106
|
-
Ok(Ok(())) => println!("Sent"),
|
|
107
|
-
Ok(Err(_)) => println!("Channel closed"),
|
|
108
|
-
Err(_) => println!("Timeout - channel full for too long"),
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// Option 4: send with permit reservation
|
|
112
|
-
let permit = tx.reserve().await?;
|
|
113
|
-
permit.send(msg); // Guaranteed to succeed
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
## Channel Types
|
|
117
|
-
|
|
118
|
-
```rust
|
|
119
|
-
// mpsc: many producers, single consumer
|
|
120
|
-
let (tx, rx) = mpsc::channel::<Message>(100);
|
|
121
|
-
let tx2 = tx.clone(); // Can clone sender
|
|
122
|
-
|
|
123
|
-
// oneshot: single value, one producer, one consumer
|
|
124
|
-
let (tx, rx) = oneshot::channel::<Response>();
|
|
125
|
-
tx.send(response); // Can only send once
|
|
126
|
-
|
|
127
|
-
// broadcast: multiple consumers, each gets all messages
|
|
128
|
-
let (tx, _) = broadcast::channel::<Event>(100);
|
|
129
|
-
let mut rx1 = tx.subscribe();
|
|
130
|
-
let mut rx2 = tx.subscribe();
|
|
131
|
-
|
|
132
|
-
// watch: single latest value, multiple consumers
|
|
133
|
-
let (tx, rx) = watch::channel::<State>(initial);
|
|
134
|
-
// Receivers see latest value, not all values
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
## Worker Pool Pattern
|
|
138
|
-
|
|
139
|
-
```rust
|
|
140
|
-
async fn process_with_workers(items: Vec<Item>) -> Vec<Result> {
|
|
141
|
-
let (tx, rx) = mpsc::channel(100);
|
|
142
|
-
let rx = Arc::new(Mutex::new(rx));
|
|
143
|
-
|
|
144
|
-
// Spawn worker pool
|
|
145
|
-
let workers: Vec<_> = (0..4).map(|_| {
|
|
146
|
-
let rx = rx.clone();
|
|
147
|
-
tokio::spawn(async move {
|
|
148
|
-
loop {
|
|
149
|
-
let item = {
|
|
150
|
-
let mut rx = rx.lock().await;
|
|
151
|
-
rx.recv().await
|
|
152
|
-
};
|
|
153
|
-
match item {
|
|
154
|
-
Some(item) => process(item).await,
|
|
155
|
-
None => break,
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
})
|
|
159
|
-
}).collect();
|
|
160
|
-
|
|
161
|
-
// Send items
|
|
162
|
-
for item in items {
|
|
163
|
-
tx.send(item).await.unwrap();
|
|
164
|
-
}
|
|
165
|
-
drop(tx); // Signal workers to stop
|
|
166
|
-
|
|
167
|
-
futures::future::join_all(workers).await;
|
|
168
|
-
}
|
|
169
|
-
```
|
|
170
|
-
|
|
171
|
-
## See Also
|
|
172
|
-
|
|
173
|
-
- [async-mpsc-queue](./async-mpsc-queue.md) - Multi-producer patterns
|
|
174
|
-
- [async-oneshot-response](./async-oneshot-response.md) - Request-response pattern
|
|
175
|
-
- [async-watch-latest](./async-watch-latest.md) - Latest-value broadcasting
|