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,105 +0,0 @@
|
|
|
1
|
-
# own-mutex-interior
|
|
2
|
-
|
|
3
|
-
> Use `Mutex<T>` for interior mutability across threads
|
|
4
|
-
|
|
5
|
-
## Why It Matters
|
|
6
|
-
|
|
7
|
-
When you need shared mutable state across threads, `Mutex<T>` provides safe interior mutability with synchronization. Unlike `RefCell`, `Mutex` is `Send + Sync` and uses OS-level locking to ensure only one thread can access the data at a time.
|
|
8
|
-
|
|
9
|
-
## Bad
|
|
10
|
-
|
|
11
|
-
```rust
|
|
12
|
-
use std::cell::RefCell;
|
|
13
|
-
use std::sync::Arc;
|
|
14
|
-
|
|
15
|
-
// RefCell is !Sync - this won't compile
|
|
16
|
-
let shared = Arc::new(RefCell::new(vec![]));
|
|
17
|
-
|
|
18
|
-
// ERROR: RefCell cannot be shared between threads safely
|
|
19
|
-
std::thread::spawn({
|
|
20
|
-
let shared = shared.clone();
|
|
21
|
-
move || shared.borrow_mut().push(1)
|
|
22
|
-
});
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
## Good
|
|
26
|
-
|
|
27
|
-
```rust
|
|
28
|
-
use std::sync::{Arc, Mutex};
|
|
29
|
-
|
|
30
|
-
let shared = Arc::new(Mutex::new(vec![]));
|
|
31
|
-
|
|
32
|
-
let handles: Vec<_> = (0..10).map(|i| {
|
|
33
|
-
let shared = shared.clone();
|
|
34
|
-
std::thread::spawn(move || {
|
|
35
|
-
let mut data = shared.lock().unwrap();
|
|
36
|
-
data.push(i);
|
|
37
|
-
})
|
|
38
|
-
}).collect();
|
|
39
|
-
|
|
40
|
-
for handle in handles {
|
|
41
|
-
handle.join().unwrap();
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
println!("{:?}", shared.lock().unwrap()); // All values present
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
## Mutex Poisoning
|
|
48
|
-
|
|
49
|
-
If a thread panics while holding a lock, the mutex becomes "poisoned":
|
|
50
|
-
|
|
51
|
-
```rust
|
|
52
|
-
use std::sync::{Arc, Mutex};
|
|
53
|
-
|
|
54
|
-
let mutex = Arc::new(Mutex::new(0));
|
|
55
|
-
|
|
56
|
-
// Handle poisoning gracefully
|
|
57
|
-
match mutex.lock() {
|
|
58
|
-
Ok(guard) => println!("Value: {}", *guard),
|
|
59
|
-
Err(poisoned) => {
|
|
60
|
-
// Recover the data anyway
|
|
61
|
-
let guard = poisoned.into_inner();
|
|
62
|
-
println!("Recovered value: {}", *guard);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// Or ignore poisoning (use with caution)
|
|
67
|
-
let guard = mutex.lock().unwrap_or_else(|e| e.into_inner());
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
## Prefer parking_lot::Mutex
|
|
71
|
-
|
|
72
|
-
For better performance, consider `parking_lot::Mutex`:
|
|
73
|
-
|
|
74
|
-
```rust
|
|
75
|
-
use parking_lot::Mutex;
|
|
76
|
-
use std::sync::Arc;
|
|
77
|
-
|
|
78
|
-
let shared = Arc::new(Mutex::new(vec![]));
|
|
79
|
-
|
|
80
|
-
// No poisoning, no Result to unwrap
|
|
81
|
-
let mut data = shared.lock();
|
|
82
|
-
data.push(42);
|
|
83
|
-
// Lock automatically released when guard drops
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
Benefits of `parking_lot`:
|
|
87
|
-
- No poisoning (returns guard directly)
|
|
88
|
-
- Smaller size (1 byte vs 40+ bytes)
|
|
89
|
-
- Better performance under contention
|
|
90
|
-
- Fair locking option available
|
|
91
|
-
|
|
92
|
-
## When to Use What
|
|
93
|
-
|
|
94
|
-
| Type | Threading | Overhead | Use Case |
|
|
95
|
-
|------|-----------|----------|----------|
|
|
96
|
-
| `RefCell<T>` | Single | Minimal | Interior mutability, same thread |
|
|
97
|
-
| `Mutex<T>` | Multi | Locking | Shared mutable state across threads |
|
|
98
|
-
| `RwLock<T>` | Multi | Locking | Many readers, few writers |
|
|
99
|
-
| `parking_lot::Mutex` | Multi | Less | Drop-in std::Mutex replacement |
|
|
100
|
-
|
|
101
|
-
## See Also
|
|
102
|
-
|
|
103
|
-
- [own-rwlock-readers](./own-rwlock-readers.md) - When reads dominate writes
|
|
104
|
-
- [own-refcell-interior](./own-refcell-interior.md) - Single-threaded alternative
|
|
105
|
-
- [async-no-lock-await](./async-no-lock-await.md) - Avoiding locks across await points
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
# own-rc-single-thread
|
|
2
|
-
|
|
3
|
-
> Use `Rc<T>` for shared ownership in single-threaded contexts
|
|
4
|
-
|
|
5
|
-
## Why It Matters
|
|
6
|
-
|
|
7
|
-
`Rc<T>` (Reference Counted) provides shared ownership without the atomic overhead of `Arc<T>`. In single-threaded code, `Rc` is faster because it uses non-atomic reference counting. Using `Arc` when you don't need thread-safety wastes CPU cycles on unnecessary synchronization.
|
|
8
|
-
|
|
9
|
-
## Bad
|
|
10
|
-
|
|
11
|
-
```rust
|
|
12
|
-
use std::sync::Arc;
|
|
13
|
-
|
|
14
|
-
// Single-threaded application using Arc unnecessarily
|
|
15
|
-
fn build_tree() -> Arc<Node> {
|
|
16
|
-
let root = Arc::new(Node::new("root"));
|
|
17
|
-
let child1 = Arc::new(Node::new("child1"));
|
|
18
|
-
let child2 = Arc::new(Node::new("child2"));
|
|
19
|
-
|
|
20
|
-
// All in same thread, but paying atomic overhead
|
|
21
|
-
root.add_child(child1.clone());
|
|
22
|
-
root.add_child(child2.clone());
|
|
23
|
-
root
|
|
24
|
-
}
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
Atomic operations have measurable overhead even without contention.
|
|
28
|
-
|
|
29
|
-
## Good
|
|
30
|
-
|
|
31
|
-
```rust
|
|
32
|
-
use std::rc::Rc;
|
|
33
|
-
|
|
34
|
-
// Single-threaded: use Rc for zero atomic overhead
|
|
35
|
-
fn build_tree() -> Rc<Node> {
|
|
36
|
-
let root = Rc::new(Node::new("root"));
|
|
37
|
-
let child1 = Rc::new(Node::new("child1"));
|
|
38
|
-
let child2 = Rc::new(Node::new("child2"));
|
|
39
|
-
|
|
40
|
-
root.add_child(child1.clone());
|
|
41
|
-
root.add_child(child2.clone());
|
|
42
|
-
root
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// Compiler enforces single-thread: Rc is !Send + !Sync
|
|
46
|
-
// Attempting to send across threads = compile error
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
## Decision Guide
|
|
50
|
-
|
|
51
|
-
| Scenario | Use |
|
|
52
|
-
|----------|-----|
|
|
53
|
-
| Single-threaded, shared ownership | `Rc<T>` |
|
|
54
|
-
| Multi-threaded, shared ownership | `Arc<T>` |
|
|
55
|
-
| Single owner, might need multiple later | Start with `Rc`, upgrade if needed |
|
|
56
|
-
| Library code, unknown threading model | `Arc<T>` (safer default) |
|
|
57
|
-
|
|
58
|
-
## Evidence
|
|
59
|
-
|
|
60
|
-
The Rust standard library itself uses `Rc` extensively in single-threaded contexts like the `std::rc` module documentation examples.
|
|
61
|
-
|
|
62
|
-
## See Also
|
|
63
|
-
|
|
64
|
-
- [own-arc-shared](./own-arc-shared.md) - When you need thread-safe sharing
|
|
65
|
-
- [own-refcell-interior](./own-refcell-interior.md) - Combining Rc with interior mutability
|
|
@@ -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
|