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,97 +0,0 @@
|
|
|
1
|
-
# own-refcell-interior
|
|
2
|
-
|
|
3
|
-
> Use `RefCell<T>` for interior mutability in single-threaded code
|
|
4
|
-
|
|
5
|
-
## Why It Matters
|
|
6
|
-
|
|
7
|
-
Rust's borrow checker enforces rules at compile time, but sometimes you need to mutate data through a shared reference. `RefCell<T>` moves borrow checking to runtime, allowing mutation through `&self`. This is essential for patterns like caches, lazy initialization, and observer patterns where compile-time borrowing is too restrictive.
|
|
8
|
-
|
|
9
|
-
## Bad
|
|
10
|
-
|
|
11
|
-
```rust
|
|
12
|
-
struct Cache {
|
|
13
|
-
// Requires &mut self to update, breaking shared reference patterns
|
|
14
|
-
data: HashMap<String, String>,
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
impl Cache {
|
|
18
|
-
fn get_or_compute(&mut self, key: &str) -> &str {
|
|
19
|
-
// Caller needs &mut Cache, can't share cache reference
|
|
20
|
-
if !self.data.contains_key(key) {
|
|
21
|
-
self.data.insert(key.to_string(), expensive_compute(key));
|
|
22
|
-
}
|
|
23
|
-
&self.data[key]
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
This forces exclusive access even for logically shared operations.
|
|
29
|
-
|
|
30
|
-
## Good
|
|
31
|
-
|
|
32
|
-
```rust
|
|
33
|
-
use std::cell::RefCell;
|
|
34
|
-
use std::collections::HashMap;
|
|
35
|
-
|
|
36
|
-
struct Cache {
|
|
37
|
-
data: RefCell<HashMap<String, String>>,
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
impl Cache {
|
|
41
|
-
fn get_or_compute(&self, key: &str) -> String {
|
|
42
|
-
// Can mutate through &self
|
|
43
|
-
let mut data = self.data.borrow_mut();
|
|
44
|
-
if !data.contains_key(key) {
|
|
45
|
-
data.insert(key.to_string(), expensive_compute(key));
|
|
46
|
-
}
|
|
47
|
-
data[key].clone()
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// Multiple references can coexist
|
|
52
|
-
let cache = Cache::new();
|
|
53
|
-
let ref1 = &cache;
|
|
54
|
-
let ref2 = &cache;
|
|
55
|
-
ref1.get_or_compute("key1");
|
|
56
|
-
ref2.get_or_compute("key2");
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
## Common Pattern: Rc<RefCell<T>>
|
|
60
|
-
|
|
61
|
-
```rust
|
|
62
|
-
use std::rc::Rc;
|
|
63
|
-
use std::cell::RefCell;
|
|
64
|
-
|
|
65
|
-
// Shared mutable state in single-threaded code
|
|
66
|
-
type SharedState = Rc<RefCell<AppState>>;
|
|
67
|
-
|
|
68
|
-
fn create_handlers(state: SharedState) -> Vec<Box<dyn Fn()>> {
|
|
69
|
-
vec![
|
|
70
|
-
Box::new({
|
|
71
|
-
let state = state.clone();
|
|
72
|
-
move || state.borrow_mut().increment()
|
|
73
|
-
}),
|
|
74
|
-
Box::new({
|
|
75
|
-
let state = state.clone();
|
|
76
|
-
move || state.borrow_mut().decrement()
|
|
77
|
-
}),
|
|
78
|
-
]
|
|
79
|
-
}
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
## Runtime Panics
|
|
83
|
-
|
|
84
|
-
`RefCell` panics if you violate borrowing rules at runtime:
|
|
85
|
-
|
|
86
|
-
```rust
|
|
87
|
-
let cell = RefCell::new(5);
|
|
88
|
-
let borrow1 = cell.borrow();
|
|
89
|
-
let borrow2 = cell.borrow_mut(); // PANIC: already borrowed
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
Use `try_borrow()` and `try_borrow_mut()` for fallible borrowing.
|
|
93
|
-
|
|
94
|
-
## See Also
|
|
95
|
-
|
|
96
|
-
- [own-rc-single-thread](./own-rc-single-thread.md) - Combining with Rc for shared ownership
|
|
97
|
-
- [own-mutex-interior](./own-mutex-interior.md) - Thread-safe alternative
|
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
# own-rwlock-readers
|
|
2
|
-
|
|
3
|
-
> Use `RwLock<T>` when reads significantly outnumber writes
|
|
4
|
-
|
|
5
|
-
## Why It Matters
|
|
6
|
-
|
|
7
|
-
`Mutex<T>` allows only one thread to access data at a time, even for reads. `RwLock<T>` allows multiple concurrent readers OR one exclusive writer. For read-heavy workloads, this dramatically improves throughput by eliminating unnecessary serialization of read operations.
|
|
8
|
-
|
|
9
|
-
## Bad
|
|
10
|
-
|
|
11
|
-
```rust
|
|
12
|
-
use std::sync::{Arc, Mutex};
|
|
13
|
-
|
|
14
|
-
// Configuration rarely changes but is read constantly
|
|
15
|
-
let config = Arc::new(Mutex::new(Config::load()));
|
|
16
|
-
|
|
17
|
-
// Every read blocks other reads unnecessarily
|
|
18
|
-
fn get_setting(config: &Mutex<Config>, key: &str) -> String {
|
|
19
|
-
let guard = config.lock().unwrap();
|
|
20
|
-
guard.get(key).to_string()
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
// 100 threads reading = serialized, one at a time
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
## Good
|
|
27
|
-
|
|
28
|
-
```rust
|
|
29
|
-
use std::sync::{Arc, RwLock};
|
|
30
|
-
|
|
31
|
-
// Multiple readers can proceed concurrently
|
|
32
|
-
let config = Arc::new(RwLock::new(Config::load()));
|
|
33
|
-
|
|
34
|
-
fn get_setting(config: &RwLock<Config>, key: &str) -> String {
|
|
35
|
-
let guard = config.read().unwrap(); // Multiple threads can hold read lock
|
|
36
|
-
guard.get(key).to_string()
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
fn update_setting(config: &RwLock<Config>, key: &str, value: &str) {
|
|
40
|
-
let mut guard = config.write().unwrap(); // Exclusive access for writes
|
|
41
|
-
guard.set(key, value);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// 100 threads reading = parallel execution
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
## parking_lot::RwLock
|
|
48
|
-
|
|
49
|
-
Prefer `parking_lot::RwLock` for better performance:
|
|
50
|
-
|
|
51
|
-
```rust
|
|
52
|
-
use parking_lot::RwLock;
|
|
53
|
-
use std::sync::Arc;
|
|
54
|
-
|
|
55
|
-
let data = Arc::new(RwLock::new(HashMap::new()));
|
|
56
|
-
|
|
57
|
-
// Read - no unwrap needed
|
|
58
|
-
let value = data.read().get("key").cloned();
|
|
59
|
-
|
|
60
|
-
// Write
|
|
61
|
-
data.write().insert("key".to_string(), "value".to_string());
|
|
62
|
-
|
|
63
|
-
// Upgradeable read lock (unique to parking_lot)
|
|
64
|
-
let upgradeable = data.upgradable_read();
|
|
65
|
-
if upgradeable.get("key").is_none() {
|
|
66
|
-
let mut write = parking_lot::RwLockUpgradableReadGuard::upgrade(upgradeable);
|
|
67
|
-
write.insert("key".to_string(), "default".to_string());
|
|
68
|
-
}
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
## When RwLock Hurts
|
|
72
|
-
|
|
73
|
-
RwLock has overhead for tracking readers. It can be slower than Mutex when:
|
|
74
|
-
|
|
75
|
-
| Scenario | Better Choice |
|
|
76
|
-
|----------|---------------|
|
|
77
|
-
| Writes are frequent (>20% of operations) | `Mutex` |
|
|
78
|
-
| Lock held very briefly | `Mutex` |
|
|
79
|
-
| Single-threaded | `RefCell` |
|
|
80
|
-
| Reads dominate, lock held longer | `RwLock` |
|
|
81
|
-
|
|
82
|
-
## Write Starvation
|
|
83
|
-
|
|
84
|
-
Standard `RwLock` may starve writers if readers are continuous. `parking_lot::RwLock` is fair by default.
|
|
85
|
-
|
|
86
|
-
```rust
|
|
87
|
-
// parking_lot is writer-fair, preventing starvation
|
|
88
|
-
use parking_lot::RwLock;
|
|
89
|
-
|
|
90
|
-
// Or use std with explicit fairness (nightly)
|
|
91
|
-
// #![feature(rwlock_downgrade)]
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
## Real-World Pattern: Cached Computation
|
|
95
|
-
|
|
96
|
-
```rust
|
|
97
|
-
use parking_lot::RwLock;
|
|
98
|
-
use std::sync::Arc;
|
|
99
|
-
|
|
100
|
-
struct CachedData {
|
|
101
|
-
cache: RwLock<Option<ExpensiveResult>>,
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
impl CachedData {
|
|
105
|
-
fn get(&self) -> ExpensiveResult {
|
|
106
|
-
// Fast path: read lock
|
|
107
|
-
if let Some(cached) = self.cache.read().as_ref() {
|
|
108
|
-
return cached.clone();
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// Slow path: compute and cache
|
|
112
|
-
let result = compute_expensive();
|
|
113
|
-
*self.cache.write() = Some(result.clone());
|
|
114
|
-
result
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
## See Also
|
|
120
|
-
|
|
121
|
-
- [own-mutex-interior](./own-mutex-interior.md) - When writes are frequent
|
|
122
|
-
- [async-no-lock-await](./async-no-lock-await.md) - RwLock in async contexts
|
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
# own-slice-over-vec
|
|
2
|
-
|
|
3
|
-
> Accept `&[T]` not `&Vec<T>`, `&str` not `&String`
|
|
4
|
-
|
|
5
|
-
## Why It Matters
|
|
6
|
-
|
|
7
|
-
Accepting `&[T]` instead of `&Vec<T>` makes your function more flexible - it can accept slices from arrays, vectors, or other sources. Similarly, `&str` accepts string slices from `String`, `&'static str`, or substrings.
|
|
8
|
-
|
|
9
|
-
## Bad
|
|
10
|
-
|
|
11
|
-
```rust
|
|
12
|
-
// Overly restrictive - only accepts &Vec
|
|
13
|
-
fn sum(numbers: &Vec<i32>) -> i32 {
|
|
14
|
-
numbers.iter().sum()
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
// Overly restrictive - only accepts &String
|
|
18
|
-
fn greet(name: &String) {
|
|
19
|
-
println!("Hello, {}", name);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
// Can't call with arrays or slices
|
|
23
|
-
let arr = [1, 2, 3];
|
|
24
|
-
// sum(&arr); // ERROR: expected &Vec<i32>
|
|
25
|
-
|
|
26
|
-
let literal = "world";
|
|
27
|
-
// greet(&literal); // ERROR: expected &String
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
## Good
|
|
31
|
-
|
|
32
|
-
```rust
|
|
33
|
-
// Flexible - accepts any slice-like thing
|
|
34
|
-
fn sum(numbers: &[i32]) -> i32 {
|
|
35
|
-
numbers.iter().sum()
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// Flexible - accepts any string-like thing
|
|
39
|
-
fn greet(name: &str) {
|
|
40
|
-
println!("Hello, {}", name);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// Now all of these work:
|
|
44
|
-
let vec = vec![1, 2, 3];
|
|
45
|
-
let arr = [4, 5, 6];
|
|
46
|
-
let slice = &vec[0..2];
|
|
47
|
-
|
|
48
|
-
sum(&vec); // Vec coerces to slice
|
|
49
|
-
sum(&arr); // Array coerces to slice
|
|
50
|
-
sum(slice); // Slice works directly
|
|
51
|
-
|
|
52
|
-
let string = String::from("Alice");
|
|
53
|
-
let literal = "Bob";
|
|
54
|
-
|
|
55
|
-
greet(&string); // String coerces to &str
|
|
56
|
-
greet(literal); // &str works directly
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
## The Deref Coercion Chain
|
|
60
|
-
|
|
61
|
-
```rust
|
|
62
|
-
// These coercions happen automatically:
|
|
63
|
-
// Vec<T> -> &[T] (via Deref)
|
|
64
|
-
// String -> &str (via Deref)
|
|
65
|
-
// Box<T> -> &T (via Deref)
|
|
66
|
-
// Arc<T> -> &T (via Deref)
|
|
67
|
-
|
|
68
|
-
fn process(data: &[u8]) { /* ... */ }
|
|
69
|
-
|
|
70
|
-
let vec: Vec<u8> = vec![1, 2, 3];
|
|
71
|
-
let boxed: Box<[u8]> = vec.into_boxed_slice();
|
|
72
|
-
let arc: Arc<[u8]> = Arc::from(&[1, 2, 3][..]);
|
|
73
|
-
|
|
74
|
-
process(&vec); // Works
|
|
75
|
-
process(&boxed); // Works
|
|
76
|
-
process(&arc); // Works
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
## Path Types Too
|
|
80
|
-
|
|
81
|
-
```rust
|
|
82
|
-
// Bad
|
|
83
|
-
fn read_config(path: &PathBuf) -> Config { /* ... */ }
|
|
84
|
-
|
|
85
|
-
// Good - accepts &Path, &PathBuf, &str, &String
|
|
86
|
-
fn read_config(path: &Path) -> Config { /* ... */ }
|
|
87
|
-
|
|
88
|
-
// Even better - accept anything path-like
|
|
89
|
-
fn read_config(path: impl AsRef<Path>) -> Config {
|
|
90
|
-
let path = path.as_ref();
|
|
91
|
-
// ...
|
|
92
|
-
}
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
## When to Accept Owned Types
|
|
96
|
-
|
|
97
|
-
```rust
|
|
98
|
-
// Accept owned when you need to store it
|
|
99
|
-
struct Logger {
|
|
100
|
-
prefix: String, // Needs to own the string
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
impl Logger {
|
|
104
|
-
// Take ownership - caller decides to clone or move
|
|
105
|
-
fn new(prefix: String) -> Self {
|
|
106
|
-
Self { prefix }
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// Or use Into for flexibility
|
|
110
|
-
fn with_prefix(prefix: impl Into<String>) -> Self {
|
|
111
|
-
Self { prefix: prefix.into() }
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
## See Also
|
|
117
|
-
|
|
118
|
-
- [api-impl-asref](api-impl-asref.md) - Accept `impl AsRef<T>` for maximum flexibility
|
|
119
|
-
- [own-borrow-over-clone](own-borrow-over-clone.md) - Prefer borrowing over cloning
|
|
@@ -1,153 +0,0 @@
|
|
|
1
|
-
# perf-black-box-bench
|
|
2
|
-
|
|
3
|
-
> Use black_box in benchmarks
|
|
4
|
-
|
|
5
|
-
## Why It Matters
|
|
6
|
-
|
|
7
|
-
The compiler aggressively optimizes code, potentially eliminating computations whose results aren't used. In benchmarks, this can lead to measuring nothing instead of the actual code. `std::hint::black_box()` prevents the compiler from optimizing away values, ensuring accurate measurements.
|
|
8
|
-
|
|
9
|
-
## Bad
|
|
10
|
-
|
|
11
|
-
```rust
|
|
12
|
-
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
|
13
|
-
|
|
14
|
-
fn benchmark_bad(c: &mut Criterion) {
|
|
15
|
-
c.bench_function("compute", |b| {
|
|
16
|
-
b.iter(|| {
|
|
17
|
-
let result = expensive_computation(42);
|
|
18
|
-
// Result unused - compiler may eliminate the call!
|
|
19
|
-
});
|
|
20
|
-
});
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
fn benchmark_also_bad(c: &mut Criterion) {
|
|
24
|
-
let input = 42; // Constant - compiler may precompute
|
|
25
|
-
|
|
26
|
-
c.bench_function("compute", |b| {
|
|
27
|
-
b.iter(|| {
|
|
28
|
-
expensive_computation(input)
|
|
29
|
-
// Return value may still be optimized away
|
|
30
|
-
});
|
|
31
|
-
});
|
|
32
|
-
}
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
## Good
|
|
36
|
-
|
|
37
|
-
```rust
|
|
38
|
-
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
|
39
|
-
|
|
40
|
-
fn benchmark_good(c: &mut Criterion) {
|
|
41
|
-
c.bench_function("compute", |b| {
|
|
42
|
-
b.iter(|| {
|
|
43
|
-
// black_box on input prevents constant folding
|
|
44
|
-
let result = expensive_computation(black_box(42));
|
|
45
|
-
// black_box on output prevents dead code elimination
|
|
46
|
-
black_box(result)
|
|
47
|
-
});
|
|
48
|
-
});
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// Or simpler with Criterion's built-in support
|
|
52
|
-
fn benchmark_simpler(c: &mut Criterion) {
|
|
53
|
-
c.bench_function("compute", |b| {
|
|
54
|
-
b.iter(|| expensive_computation(black_box(42)))
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
## What black_box Does
|
|
60
|
-
|
|
61
|
-
| Without black_box | With black_box |
|
|
62
|
-
|-------------------|----------------|
|
|
63
|
-
| Input may be constant-folded | Input treated as unknown |
|
|
64
|
-
| Result may be eliminated | Result must be computed |
|
|
65
|
-
| Loops may be optimized away | Each iteration runs |
|
|
66
|
-
| Functions may be inlined | Call semantics preserved |
|
|
67
|
-
|
|
68
|
-
## Standard Library Usage
|
|
69
|
-
|
|
70
|
-
```rust
|
|
71
|
-
use std::hint::black_box;
|
|
72
|
-
|
|
73
|
-
fn main() {
|
|
74
|
-
// In std since Rust 1.66
|
|
75
|
-
let result = black_box(compute_something(black_box(input)));
|
|
76
|
-
}
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
## Criterion's black_box
|
|
80
|
-
|
|
81
|
-
Criterion re-exports `std::hint::black_box`:
|
|
82
|
-
|
|
83
|
-
```rust
|
|
84
|
-
use criterion::black_box;
|
|
85
|
-
|
|
86
|
-
// Equivalent to std::hint::black_box
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
## Pattern: Benchmark with Setup
|
|
90
|
-
|
|
91
|
-
```rust
|
|
92
|
-
fn benchmark_with_setup(c: &mut Criterion) {
|
|
93
|
-
c.bench_function("process_data", |b| {
|
|
94
|
-
// Setup outside iter - not measured
|
|
95
|
-
let data = generate_test_data(1000);
|
|
96
|
-
|
|
97
|
-
b.iter(|| {
|
|
98
|
-
// black_box the input reference
|
|
99
|
-
let result = process(black_box(&data));
|
|
100
|
-
black_box(result)
|
|
101
|
-
});
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
## Pattern: Benchmark Multiple Inputs
|
|
107
|
-
|
|
108
|
-
```rust
|
|
109
|
-
fn benchmark_sizes(c: &mut Criterion) {
|
|
110
|
-
let mut group = c.benchmark_group("scaling");
|
|
111
|
-
|
|
112
|
-
for size in [100, 1000, 10000] {
|
|
113
|
-
let data = generate_data(size);
|
|
114
|
-
|
|
115
|
-
group.bench_with_input(
|
|
116
|
-
BenchmarkId::from_parameter(size),
|
|
117
|
-
&data,
|
|
118
|
-
|b, data| {
|
|
119
|
-
b.iter(|| process(black_box(data)))
|
|
120
|
-
},
|
|
121
|
-
);
|
|
122
|
-
}
|
|
123
|
-
group.finish();
|
|
124
|
-
}
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
## Common Mistakes
|
|
128
|
-
|
|
129
|
-
```rust
|
|
130
|
-
// WRONG: black_box inside loop does nothing useful
|
|
131
|
-
for _ in 0..1000 {
|
|
132
|
-
black_box(()); // Doesn't help
|
|
133
|
-
compute();
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
// RIGHT: black_box the computation result
|
|
137
|
-
for _ in 0..1000 {
|
|
138
|
-
black_box(compute());
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
// WRONG: Only blocking output, not input
|
|
142
|
-
let x = 42; // Constant, may be optimized
|
|
143
|
-
black_box(expensive(x));
|
|
144
|
-
|
|
145
|
-
// RIGHT: Block both
|
|
146
|
-
black_box(expensive(black_box(42)));
|
|
147
|
-
```
|
|
148
|
-
|
|
149
|
-
## See Also
|
|
150
|
-
|
|
151
|
-
- [test-criterion-bench](./test-criterion-bench.md) - Using Criterion
|
|
152
|
-
- [perf-profile-first](./perf-profile-first.md) - Profile before optimize
|
|
153
|
-
- [perf-release-profile](./perf-release-profile.md) - Release settings
|
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
# perf-chain-avoid
|
|
2
|
-
|
|
3
|
-
> Avoid chain in hot loops
|
|
4
|
-
|
|
5
|
-
## Why It Matters
|
|
6
|
-
|
|
7
|
-
`Iterator::chain()` adds overhead for checking which iterator is active on every `.next()` call. In hot loops, this branch prediction overhead can impact performance. For performance-critical code, prefer single iterators or pre-combined collections.
|
|
8
|
-
|
|
9
|
-
## Bad
|
|
10
|
-
|
|
11
|
-
```rust
|
|
12
|
-
// Chain in hot inner loop
|
|
13
|
-
fn process_hot_path(a: &[i32], b: &[i32]) -> i64 {
|
|
14
|
-
let mut sum = 0i64;
|
|
15
|
-
|
|
16
|
-
// Called millions of times
|
|
17
|
-
for _ in 0..1_000_000 {
|
|
18
|
-
for x in a.iter().chain(b.iter()) { // Branch every iteration
|
|
19
|
-
sum += *x as i64;
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
sum
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
// Chaining multiple small slices in tight loop
|
|
26
|
-
fn combine_results(parts: &[&[u8]]) -> Vec<u8> {
|
|
27
|
-
let mut result = Vec::new();
|
|
28
|
-
for part in parts {
|
|
29
|
-
for byte in std::iter::once(&0u8).chain(part.iter()) {
|
|
30
|
-
result.push(*byte);
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
result
|
|
34
|
-
}
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
## Good
|
|
38
|
-
|
|
39
|
-
```rust
|
|
40
|
-
// Separate loops - branch-free inner loops
|
|
41
|
-
fn process_hot_path(a: &[i32], b: &[i32]) -> i64 {
|
|
42
|
-
let mut sum = 0i64;
|
|
43
|
-
|
|
44
|
-
for _ in 0..1_000_000 {
|
|
45
|
-
for x in a {
|
|
46
|
-
sum += *x as i64;
|
|
47
|
-
}
|
|
48
|
-
for x in b {
|
|
49
|
-
sum += *x as i64;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
sum
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// Pre-combine outside hot loop
|
|
56
|
-
fn combine_results(parts: &[&[u8]]) -> Vec<u8> {
|
|
57
|
-
let mut result = Vec::new();
|
|
58
|
-
for part in parts {
|
|
59
|
-
result.push(0u8);
|
|
60
|
-
result.extend_from_slice(part);
|
|
61
|
-
}
|
|
62
|
-
result
|
|
63
|
-
}
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
## When Chain Is Fine
|
|
67
|
-
|
|
68
|
-
Chain is perfectly acceptable when:
|
|
69
|
-
|
|
70
|
-
```rust
|
|
71
|
-
// One-time iteration, not in hot path
|
|
72
|
-
fn collect_all(a: Vec<i32>, b: Vec<i32>) -> Vec<i32> {
|
|
73
|
-
a.into_iter().chain(b).collect()
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// Lazy evaluation with short-circuit
|
|
77
|
-
fn find_in_either(a: &[Item], b: &[Item], target: i32) -> Option<&Item> {
|
|
78
|
-
a.iter().chain(b.iter()).find(|x| x.id == target)
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// Small number of elements
|
|
82
|
-
fn get_prefixes() -> impl Iterator<Item = &'static str> {
|
|
83
|
-
["Mr.", "Mrs.", "Dr."].iter().copied()
|
|
84
|
-
.chain(["Prof."].iter().copied())
|
|
85
|
-
}
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
## Alternative Patterns
|
|
89
|
-
|
|
90
|
-
### Pre-allocate and Extend
|
|
91
|
-
|
|
92
|
-
```rust
|
|
93
|
-
fn merge_slices(slices: &[&[i32]]) -> Vec<i32> {
|
|
94
|
-
let total: usize = slices.iter().map(|s| s.len()).sum();
|
|
95
|
-
let mut result = Vec::with_capacity(total);
|
|
96
|
-
for slice in slices {
|
|
97
|
-
result.extend_from_slice(slice);
|
|
98
|
-
}
|
|
99
|
-
result
|
|
100
|
-
}
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
### Use append for Vecs
|
|
104
|
-
|
|
105
|
-
```rust
|
|
106
|
-
fn combine_vecs(mut a: Vec<i32>, mut b: Vec<i32>) -> Vec<i32> {
|
|
107
|
-
a.append(&mut b); // Moves elements, no reallocation if a has capacity
|
|
108
|
-
a
|
|
109
|
-
}
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
### Flatten Instead of Chain
|
|
113
|
-
|
|
114
|
-
```rust
|
|
115
|
-
// Instead of: a.iter().chain(b.iter()).chain(c.iter())
|
|
116
|
-
let all = [a, b, c];
|
|
117
|
-
for item in all.iter().flat_map(|slice| slice.iter()) {
|
|
118
|
-
process(item);
|
|
119
|
-
}
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
## Performance Impact
|
|
123
|
-
|
|
124
|
-
| Pattern | Per-Item Overhead |
|
|
125
|
-
|---------|-------------------|
|
|
126
|
-
| Single iterator | None |
|
|
127
|
-
| `chain(a, b)` | 1 branch per item |
|
|
128
|
-
| `chain(a, b, c)` | 2 branches per item |
|
|
129
|
-
| Nested chains | Compounds |
|
|
130
|
-
| Separate loops | None (but code duplication) |
|
|
131
|
-
|
|
132
|
-
## See Also
|
|
133
|
-
|
|
134
|
-
- [perf-iter-over-index](./perf-iter-over-index.md) - Prefer iterators
|
|
135
|
-
- [perf-extend-batch](./perf-extend-batch.md) - Batch insertions
|
|
136
|
-
- [opt-cache-friendly](./opt-cache-friendly.md) - Cache-friendly patterns
|