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,135 +0,0 @@
|
|
|
1
|
-
# own-clone-explicit
|
|
2
|
-
|
|
3
|
-
> Use explicit `Clone` for types where copying has meaningful cost
|
|
4
|
-
|
|
5
|
-
## Why It Matters
|
|
6
|
-
|
|
7
|
-
Unlike `Copy` which is implicit and "free," `Clone` requires an explicit `.clone()` call, signaling that duplication has a cost. This makes heap allocations and deep copies visible in code, helping developers reason about performance. Types with heap data (`String`, `Vec`, `Box`) should implement `Clone` but not `Copy`.
|
|
8
|
-
|
|
9
|
-
## Bad
|
|
10
|
-
|
|
11
|
-
```rust
|
|
12
|
-
// Hiding expensive operations
|
|
13
|
-
fn process_data(data: Vec<u32>) -> Vec<u32> {
|
|
14
|
-
let backup = data; // Moved, not copied - but unclear at call site
|
|
15
|
-
transform(backup)
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
let my_data = vec![1, 2, 3, 4, 5];
|
|
19
|
-
let result = process_data(my_data);
|
|
20
|
-
// my_data is moved - surprise if you expected it to still exist
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
## Good
|
|
24
|
-
|
|
25
|
-
```rust
|
|
26
|
-
fn process_data(data: Vec<u32>) -> Vec<u32> {
|
|
27
|
-
let backup = data;
|
|
28
|
-
transform(backup)
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
let my_data = vec![1, 2, 3, 4, 5];
|
|
32
|
-
let result = process_data(my_data.clone()); // Explicit: "I know this allocates"
|
|
33
|
-
// my_data still available
|
|
34
|
-
|
|
35
|
-
// Or better - take reference if you don't need ownership
|
|
36
|
-
fn process_data_ref(data: &[u32]) -> Vec<u32> {
|
|
37
|
-
transform(data)
|
|
38
|
-
}
|
|
39
|
-
let result = process_data_ref(&my_data); // No clone needed
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
## Custom Clone Implementation
|
|
43
|
-
|
|
44
|
-
For types with mixed cheap/expensive fields, implement `Clone` manually:
|
|
45
|
-
|
|
46
|
-
```rust
|
|
47
|
-
#[derive(Debug)]
|
|
48
|
-
struct Document {
|
|
49
|
-
id: u64, // Cheap to copy
|
|
50
|
-
content: String, // Expensive to clone
|
|
51
|
-
metadata: Metadata, // Moderate cost
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
impl Clone for Document {
|
|
55
|
-
fn clone(&self) -> Self {
|
|
56
|
-
Self {
|
|
57
|
-
id: self.id,
|
|
58
|
-
content: self.content.clone(),
|
|
59
|
-
metadata: self.metadata.clone(),
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// Optimization: reuse existing allocations
|
|
64
|
-
fn clone_from(&mut self, source: &Self) {
|
|
65
|
-
self.id = source.id;
|
|
66
|
-
self.content.clone_from(&source.content); // Reuses capacity
|
|
67
|
-
self.metadata.clone_from(&source.metadata);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
## clone_from Optimization
|
|
73
|
-
|
|
74
|
-
`clone_from` can reuse existing allocations:
|
|
75
|
-
|
|
76
|
-
```rust
|
|
77
|
-
let mut buffer = String::with_capacity(1000);
|
|
78
|
-
|
|
79
|
-
// Bad: drops old allocation, creates new one
|
|
80
|
-
buffer = source.clone();
|
|
81
|
-
|
|
82
|
-
// Good: reuses existing capacity if sufficient
|
|
83
|
-
buffer.clone_from(&source);
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
## Derive vs Manual Clone
|
|
87
|
-
|
|
88
|
-
```rust
|
|
89
|
-
// Derive when all fields need cloning
|
|
90
|
-
#[derive(Clone)]
|
|
91
|
-
struct Simple {
|
|
92
|
-
data: Vec<u8>,
|
|
93
|
-
name: String,
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// Manual when you need special behavior
|
|
97
|
-
struct CachedValue {
|
|
98
|
-
value: i32,
|
|
99
|
-
cache: RefCell<Option<ExpensiveComputation>>,
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
impl Clone for CachedValue {
|
|
103
|
-
fn clone(&self) -> Self {
|
|
104
|
-
Self {
|
|
105
|
-
value: self.value,
|
|
106
|
-
cache: RefCell::new(None), // Don't clone cache, let it rebuild
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
## When to Avoid Clone
|
|
113
|
-
|
|
114
|
-
```rust
|
|
115
|
-
// Instead of cloning, consider:
|
|
116
|
-
|
|
117
|
-
// 1. References
|
|
118
|
-
fn process(data: &MyType) { } // Borrow instead of clone
|
|
119
|
-
|
|
120
|
-
// 2. Cow for conditional cloning
|
|
121
|
-
fn process(data: Cow<'_, str>) { } // Clone only if mutation needed
|
|
122
|
-
|
|
123
|
-
// 3. Arc for shared ownership
|
|
124
|
-
let shared = Arc::new(expensive_data);
|
|
125
|
-
let handle = shared.clone(); // Cheap: just increments counter
|
|
126
|
-
|
|
127
|
-
// 4. Passing by value when caller is done with it
|
|
128
|
-
fn consume(data: MyType) { } // Caller moves, no clone
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
## See Also
|
|
132
|
-
|
|
133
|
-
- [own-copy-small](./own-copy-small.md) - When implicit Copy is appropriate
|
|
134
|
-
- [own-cow-conditional](./own-cow-conditional.md) - Avoiding clones with Cow
|
|
135
|
-
- [mem-clone-from](./mem-clone-from.md) - Optimizing repeated clones
|
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
# own-copy-small
|
|
2
|
-
|
|
3
|
-
> Implement `Copy` for small, simple types
|
|
4
|
-
|
|
5
|
-
## Why It Matters
|
|
6
|
-
|
|
7
|
-
Types that implement `Copy` are implicitly duplicated on assignment instead of moved. This eliminates the need for explicit `.clone()` calls and makes the code more ergonomic. For small types (generally ≤16 bytes), copying is as fast or faster than moving a pointer.
|
|
8
|
-
|
|
9
|
-
## Bad
|
|
10
|
-
|
|
11
|
-
```rust
|
|
12
|
-
// Small type without Copy - requires explicit clone
|
|
13
|
-
#[derive(Clone, Debug)]
|
|
14
|
-
struct Point {
|
|
15
|
-
x: f64,
|
|
16
|
-
y: f64,
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
fn distance(p1: Point, p2: Point) -> f64 {
|
|
20
|
-
((p2.x - p1.x).powi(2) + (p2.y - p1.y).powi(2)).sqrt()
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
let origin = Point { x: 0.0, y: 0.0 };
|
|
24
|
-
let target = Point { x: 3.0, y: 4.0 };
|
|
25
|
-
|
|
26
|
-
let d1 = distance(origin.clone(), target.clone()); // Tedious
|
|
27
|
-
let d2 = distance(origin.clone(), target.clone()); // Every use needs clone
|
|
28
|
-
// origin and target still usable but verbose
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
## Good
|
|
32
|
-
|
|
33
|
-
```rust
|
|
34
|
-
// Small type with Copy - implicit duplication
|
|
35
|
-
#[derive(Clone, Copy, Debug)]
|
|
36
|
-
struct Point {
|
|
37
|
-
x: f64,
|
|
38
|
-
y: f64,
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
fn distance(p1: Point, p2: Point) -> f64 {
|
|
42
|
-
((p2.x - p1.x).powi(2) + (p2.y - p1.y).powi(2)).sqrt()
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
let origin = Point { x: 0.0, y: 0.0 };
|
|
46
|
-
let target = Point { x: 3.0, y: 4.0 };
|
|
47
|
-
|
|
48
|
-
let d1 = distance(origin, target); // Implicitly copied
|
|
49
|
-
let d2 = distance(origin, target); // Still works!
|
|
50
|
-
// origin and target remain valid
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
## Copy Requirements
|
|
54
|
-
|
|
55
|
-
A type can implement `Copy` only if:
|
|
56
|
-
1. All fields implement `Copy`
|
|
57
|
-
2. No custom `Drop` implementation
|
|
58
|
-
3. No heap-allocated data (`String`, `Vec`, `Box`, etc.)
|
|
59
|
-
|
|
60
|
-
```rust
|
|
61
|
-
// ✅ Can be Copy
|
|
62
|
-
#[derive(Clone, Copy)]
|
|
63
|
-
struct Color {
|
|
64
|
-
r: u8,
|
|
65
|
-
g: u8,
|
|
66
|
-
b: u8,
|
|
67
|
-
a: u8,
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// ❌ Cannot be Copy - contains String
|
|
71
|
-
#[derive(Clone)]
|
|
72
|
-
struct Person {
|
|
73
|
-
name: String, // String is not Copy
|
|
74
|
-
age: u32,
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
// ❌ Cannot be Copy - has Drop
|
|
78
|
-
struct FileHandle {
|
|
79
|
-
fd: i32,
|
|
80
|
-
}
|
|
81
|
-
impl Drop for FileHandle {
|
|
82
|
-
fn drop(&mut self) { /* close file */ }
|
|
83
|
-
}
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
## Size Guidelines
|
|
87
|
-
|
|
88
|
-
| Size | Recommendation |
|
|
89
|
-
|------|----------------|
|
|
90
|
-
| ≤ 16 bytes | Implement `Copy` |
|
|
91
|
-
| 17-64 bytes | Consider `Copy`, benchmark if critical |
|
|
92
|
-
| > 64 bytes | Probably don't, prefer references |
|
|
93
|
-
|
|
94
|
-
```rust
|
|
95
|
-
use std::mem::size_of;
|
|
96
|
-
|
|
97
|
-
#[derive(Clone, Copy)]
|
|
98
|
-
struct SmallId(u64); // 8 bytes ✅
|
|
99
|
-
|
|
100
|
-
#[derive(Clone, Copy)]
|
|
101
|
-
struct Rect { x: f32, y: f32, w: f32, h: f32 } // 16 bytes ✅
|
|
102
|
-
|
|
103
|
-
#[derive(Clone)] // No Copy - 72 bytes
|
|
104
|
-
struct Transform {
|
|
105
|
-
matrix: [[f64; 3]; 3], // 72 bytes, too large
|
|
106
|
-
}
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
## Common Copy Types
|
|
110
|
-
|
|
111
|
-
Standard library types that are `Copy`:
|
|
112
|
-
- All primitives: `i32`, `f64`, `bool`, `char`, etc.
|
|
113
|
-
- References: `&T`, `&mut T`
|
|
114
|
-
- Raw pointers: `*const T`, `*mut T`
|
|
115
|
-
- Function pointers: `fn(T) -> U`
|
|
116
|
-
- Tuples of `Copy` types: `(i32, f64)`
|
|
117
|
-
- Arrays of `Copy` types: `[u8; 32]`
|
|
118
|
-
- `Option<T>` where `T: Copy`
|
|
119
|
-
- `PhantomData<T>`
|
|
120
|
-
|
|
121
|
-
## See Also
|
|
122
|
-
|
|
123
|
-
- [own-clone-explicit](./own-clone-explicit.md) - When Clone without Copy is appropriate
|
|
124
|
-
- [type-newtype-ids](./type-newtype-ids.md) - Newtype pattern often uses Copy
|
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
# own-cow-conditional
|
|
2
|
-
|
|
3
|
-
> Use `Cow<'a, T>` for conditional ownership
|
|
4
|
-
|
|
5
|
-
## Why It Matters
|
|
6
|
-
|
|
7
|
-
`Cow` (Clone-on-Write) lets you avoid allocations when you *might* need to own data but usually don't. It holds either a borrowed reference or an owned value, cloning only when mutation is needed.
|
|
8
|
-
|
|
9
|
-
## Bad
|
|
10
|
-
|
|
11
|
-
```rust
|
|
12
|
-
// Always allocates, even when input doesn't need modification
|
|
13
|
-
fn normalize_path(path: &str) -> String {
|
|
14
|
-
if path.contains("//") {
|
|
15
|
-
path.replace("//", "/") // Allocation needed
|
|
16
|
-
} else {
|
|
17
|
-
path.to_string() // Unnecessary allocation!
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
// Always clones the error message
|
|
22
|
-
fn format_error(code: u32) -> String {
|
|
23
|
-
match code {
|
|
24
|
-
404 => "Not Found".to_string(), // Unnecessary!
|
|
25
|
-
500 => "Internal Error".to_string(), // Unnecessary!
|
|
26
|
-
_ => format!("Error {}", code), // This one needs allocation
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
## Good
|
|
32
|
-
|
|
33
|
-
```rust
|
|
34
|
-
use std::borrow::Cow;
|
|
35
|
-
|
|
36
|
-
// Only allocates when needed
|
|
37
|
-
fn normalize_path(path: &str) -> Cow<'_, str> {
|
|
38
|
-
if path.contains("//") {
|
|
39
|
-
Cow::Owned(path.replace("//", "/")) // Allocate
|
|
40
|
-
} else {
|
|
41
|
-
Cow::Borrowed(path) // Zero-cost borrow
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// Static strings stay borrowed
|
|
46
|
-
fn format_error(code: u32) -> Cow<'static, str> {
|
|
47
|
-
match code {
|
|
48
|
-
404 => Cow::Borrowed("Not Found"), // No allocation
|
|
49
|
-
500 => Cow::Borrowed("Internal Error"), // No allocation
|
|
50
|
-
_ => Cow::Owned(format!("Error {}", code)), // Allocate only for unknown
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
## Real-World Example from ripgrep
|
|
56
|
-
|
|
57
|
-
```rust
|
|
58
|
-
// https://github.com/BurntSushi/ripgrep/blob/master/crates/globset/src/pathutil.rs
|
|
59
|
-
pub(crate) fn file_name<'a>(path: &Cow<'a, [u8]>) -> Option<Cow<'a, [u8]>> {
|
|
60
|
-
let last_slash = path.rfind_byte(b'/').map(|i| i + 1).unwrap_or(0);
|
|
61
|
-
match *path {
|
|
62
|
-
Cow::Borrowed(path) => Some(Cow::Borrowed(&path[last_slash..])),
|
|
63
|
-
Cow::Owned(ref path) => {
|
|
64
|
-
let mut path = path.clone();
|
|
65
|
-
path.drain_bytes(..last_slash);
|
|
66
|
-
Some(Cow::Owned(path))
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
## Clone-on-Write Pattern
|
|
73
|
-
|
|
74
|
-
```rust
|
|
75
|
-
use std::borrow::Cow;
|
|
76
|
-
|
|
77
|
-
fn process_text(text: Cow<'_, str>) -> Cow<'_, str> {
|
|
78
|
-
if text.contains("bad_word") {
|
|
79
|
-
// to_mut() clones if borrowed, returns &mut if owned
|
|
80
|
-
let mut owned = text.into_owned();
|
|
81
|
-
owned = owned.replace("bad_word", "***");
|
|
82
|
-
Cow::Owned(owned)
|
|
83
|
-
} else {
|
|
84
|
-
text // Pass through unchanged
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
// Usage
|
|
89
|
-
let borrowed: Cow<str> = Cow::Borrowed("hello world");
|
|
90
|
-
let result = process_text(borrowed); // No allocation!
|
|
91
|
-
|
|
92
|
-
let with_bad: Cow<str> = Cow::Borrowed("hello bad_word");
|
|
93
|
-
let result = process_text(with_bad); // Allocates only here
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
## Cow with Collections
|
|
97
|
-
|
|
98
|
-
```rust
|
|
99
|
-
use std::borrow::Cow;
|
|
100
|
-
|
|
101
|
-
// Mixed borrowed/owned in a collection
|
|
102
|
-
fn collect_errors<'a>(
|
|
103
|
-
static_errors: &[&'static str],
|
|
104
|
-
dynamic_errors: Vec<String>,
|
|
105
|
-
) -> Vec<Cow<'a, str>> {
|
|
106
|
-
let mut errors: Vec<Cow<str>> = Vec::new();
|
|
107
|
-
|
|
108
|
-
// Static strings - no allocation
|
|
109
|
-
for &e in static_errors {
|
|
110
|
-
errors.push(Cow::Borrowed(e));
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
// Dynamic strings - take ownership
|
|
114
|
-
for e in dynamic_errors {
|
|
115
|
-
errors.push(Cow::Owned(e));
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
errors
|
|
119
|
-
}
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
## When to Use Cow
|
|
123
|
-
|
|
124
|
-
| Situation | Use Cow? |
|
|
125
|
-
|-----------|----------|
|
|
126
|
-
| Usually borrow, sometimes own | Yes |
|
|
127
|
-
| Always need owned data | No, just use owned type |
|
|
128
|
-
| Always borrow | No, just use reference |
|
|
129
|
-
| Hot path, avoiding all allocations | Yes |
|
|
130
|
-
| Returning static strings or formatted | Yes |
|
|
131
|
-
|
|
132
|
-
## See Also
|
|
133
|
-
|
|
134
|
-
- [own-borrow-over-clone](own-borrow-over-clone.md) - Prefer borrowing over cloning
|
|
135
|
-
- [mem-avoid-format](mem-avoid-format.md) - Avoid format! when possible
|
|
@@ -1,134 +0,0 @@
|
|
|
1
|
-
# own-lifetime-elision
|
|
2
|
-
|
|
3
|
-
> Rely on lifetime elision rules; add explicit lifetimes only when required
|
|
4
|
-
|
|
5
|
-
## Why It Matters
|
|
6
|
-
|
|
7
|
-
Rust's lifetime elision rules handle most common borrowing patterns automatically. Adding explicit lifetimes where they're not needed clutters code without adding clarity. However, understanding when elision applies helps you know when explicit lifetimes are truly necessary.
|
|
8
|
-
|
|
9
|
-
## Bad
|
|
10
|
-
|
|
11
|
-
```rust
|
|
12
|
-
// Unnecessary explicit lifetimes - elision handles these
|
|
13
|
-
fn first_word<'a>(s: &'a str) -> &'a str {
|
|
14
|
-
s.split_whitespace().next().unwrap_or("")
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
fn get_name<'a>(person: &'a Person) -> &'a str {
|
|
18
|
-
&person.name
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
impl<'a> Display for Wrapper<'a> {
|
|
22
|
-
fn fmt<'b>(&'b self, f: &'b mut Formatter<'_>) -> fmt::Result {
|
|
23
|
-
write!(f, "{}", self.0)
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
## Good
|
|
29
|
-
|
|
30
|
-
```rust
|
|
31
|
-
// Let elision do its job
|
|
32
|
-
fn first_word(s: &str) -> &str {
|
|
33
|
-
s.split_whitespace().next().unwrap_or("")
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
fn get_name(person: &Person) -> &str {
|
|
37
|
-
&person.name
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
impl Display for Wrapper<'_> {
|
|
41
|
-
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
|
42
|
-
write!(f, "{}", self.0)
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
## The Three Elision Rules
|
|
48
|
-
|
|
49
|
-
1. **Each input reference gets its own lifetime:**
|
|
50
|
-
```rust
|
|
51
|
-
fn foo(x: &str, y: &str)
|
|
52
|
-
// becomes
|
|
53
|
-
fn foo<'a, 'b>(x: &'a str, y: &'b str)
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
2. **One input reference → output gets same lifetime:**
|
|
57
|
-
```rust
|
|
58
|
-
fn foo(x: &str) -> &str
|
|
59
|
-
// becomes
|
|
60
|
-
fn foo<'a>(x: &'a str) -> &'a str
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
3. **Method with `&self`/`&mut self` → output gets self's lifetime:**
|
|
64
|
-
```rust
|
|
65
|
-
fn foo(&self, x: &str) -> &str
|
|
66
|
-
// becomes
|
|
67
|
-
fn foo<'a, 'b>(&'a self, x: &'b str) -> &'a str
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
## When Explicit Lifetimes ARE Required
|
|
71
|
-
|
|
72
|
-
```rust
|
|
73
|
-
// Multiple input references, output could come from either
|
|
74
|
-
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
|
|
75
|
-
if x.len() > y.len() { x } else { y }
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// Struct holding references
|
|
79
|
-
struct Parser<'input> {
|
|
80
|
-
source: &'input str,
|
|
81
|
-
position: usize,
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// Multiple distinct lifetimes needed
|
|
85
|
-
struct Context<'s, 'c> {
|
|
86
|
-
source: &'s str,
|
|
87
|
-
cache: &'c mut Cache,
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// Static lifetime for constants
|
|
91
|
-
fn get_default() -> &'static str {
|
|
92
|
-
"default"
|
|
93
|
-
}
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
## Anonymous Lifetime `'_`
|
|
97
|
-
|
|
98
|
-
Use `'_` to let the compiler infer while being explicit about the presence of a lifetime:
|
|
99
|
-
|
|
100
|
-
```rust
|
|
101
|
-
// In struct definitions
|
|
102
|
-
impl Iterator for Parser<'_> {
|
|
103
|
-
type Item = Token;
|
|
104
|
-
fn next(&mut self) -> Option<Self::Item> { ... }
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
// In function signatures where it adds clarity
|
|
108
|
-
fn parse(input: &str) -> Result<Ast<'_>, Error> { ... }
|
|
109
|
-
|
|
110
|
-
// Especially useful in trait bounds
|
|
111
|
-
fn process(data: &impl AsRef<str>) -> Cow<'_, str> { ... }
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
## Common Patterns
|
|
115
|
-
|
|
116
|
-
```rust
|
|
117
|
-
// ✅ Elision works
|
|
118
|
-
fn trim(s: &str) -> &str { s.trim() }
|
|
119
|
-
fn first(v: &[i32]) -> Option<&i32> { v.first() }
|
|
120
|
-
fn name(&self) -> &str { &self.name }
|
|
121
|
-
|
|
122
|
-
// ❌ Elision fails - multiple inputs, ambiguous output
|
|
123
|
-
fn pick(a: &str, b: &str, first: bool) -> &str // Error!
|
|
124
|
-
|
|
125
|
-
// ✅ Fixed with explicit lifetime
|
|
126
|
-
fn pick<'a>(a: &'a str, b: &'a str, first: bool) -> &'a str {
|
|
127
|
-
if first { a } else { b }
|
|
128
|
-
}
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
## See Also
|
|
132
|
-
|
|
133
|
-
- [own-borrow-over-clone](./own-borrow-over-clone.md) - Prefer borrowing to avoid ownership issues
|
|
134
|
-
- [api-impl-asref](./api-impl-asref.md) - Generic borrowing with AsRef
|
|
@@ -1,134 +0,0 @@
|
|
|
1
|
-
# own-move-large
|
|
2
|
-
|
|
3
|
-
> Move large types instead of copying; use `Box` if moves are expensive
|
|
4
|
-
|
|
5
|
-
## Why It Matters
|
|
6
|
-
|
|
7
|
-
In Rust, "moving" a value means copying its bytes to a new location and invalidating the old one. For large types (hundreds of bytes), this memcpy can be expensive. Boxing large types reduces move cost to copying a single pointer (8 bytes), making moves cheap regardless of the actual data size.
|
|
8
|
-
|
|
9
|
-
## Bad
|
|
10
|
-
|
|
11
|
-
```rust
|
|
12
|
-
// Large struct moved repeatedly = expensive memcpy each time
|
|
13
|
-
struct GameState {
|
|
14
|
-
board: [[Cell; 100]; 100], // 10,000 cells
|
|
15
|
-
history: [Move; 1000], // 1,000 moves
|
|
16
|
-
players: [Player; 4], // Player data
|
|
17
|
-
// Total: potentially tens of KB
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
fn process_state(state: GameState) -> GameState {
|
|
21
|
-
// Moving ~40KB+ of data
|
|
22
|
-
let mut new_state = state; // Memcpy here
|
|
23
|
-
new_state.apply_rules();
|
|
24
|
-
new_state // Memcpy on return
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
let state = GameState::new();
|
|
28
|
-
let state = process_state(state); // Two large memcpys
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
## Good
|
|
32
|
-
|
|
33
|
-
```rust
|
|
34
|
-
// Box reduces move cost to 8 bytes
|
|
35
|
-
struct GameState {
|
|
36
|
-
board: Box<[[Cell; 100]; 100]>, // Pointer to heap
|
|
37
|
-
history: Vec<Move>, // Already heap-allocated
|
|
38
|
-
players: [Player; 4],
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
fn process_state(mut state: GameState) -> GameState {
|
|
42
|
-
// Moving just pointers + small inline data
|
|
43
|
-
state.apply_rules();
|
|
44
|
-
state // Cheap move
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// Or use Box at call site for one-off cases
|
|
48
|
-
fn process_large(state: Box<LargeStruct>) -> Box<LargeStruct> {
|
|
49
|
-
// 8-byte move regardless of LargeStruct size
|
|
50
|
-
state
|
|
51
|
-
}
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
## When to Box
|
|
55
|
-
|
|
56
|
-
| Type Size | Move Frequency | Recommendation |
|
|
57
|
-
|-----------|----------------|----------------|
|
|
58
|
-
| < 128 bytes | Any | Don't box |
|
|
59
|
-
| 128-512 bytes | Rare | Probably don't box |
|
|
60
|
-
| 128-512 bytes | Frequent | Consider boxing |
|
|
61
|
-
| > 512 bytes | Any | Box or use references |
|
|
62
|
-
| > 4KB | Any | Definitely box |
|
|
63
|
-
|
|
64
|
-
## Stack vs Heap Tradeoffs
|
|
65
|
-
|
|
66
|
-
```rust
|
|
67
|
-
// Stack: fast allocation, limited size, moves copy bytes
|
|
68
|
-
struct StackHeavy {
|
|
69
|
-
data: [u8; 4096], // 4KB on stack
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// Heap: allocation cost, unlimited size, moves copy pointer
|
|
73
|
-
struct HeapLight {
|
|
74
|
-
data: Box<[u8; 4096]>, // 8 bytes on stack, 4KB on heap
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
// Measure with size_of
|
|
78
|
-
use std::mem::size_of;
|
|
79
|
-
assert_eq!(size_of::<StackHeavy>(), 4096);
|
|
80
|
-
assert_eq!(size_of::<HeapLight>(), 8);
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
## Alternative: References
|
|
84
|
-
|
|
85
|
-
When you don't need ownership transfer, use references:
|
|
86
|
-
|
|
87
|
-
```rust
|
|
88
|
-
// Best: no move at all
|
|
89
|
-
fn analyze_state(state: &GameState) -> Analysis {
|
|
90
|
-
// Borrows state, no copying
|
|
91
|
-
compute_analysis(state)
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// Mutable borrow for in-place modification
|
|
95
|
-
fn update_state(state: &mut GameState) {
|
|
96
|
-
state.tick();
|
|
97
|
-
}
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
## Pattern: Builder Returns Boxed
|
|
101
|
-
|
|
102
|
-
```rust
|
|
103
|
-
impl LargeConfig {
|
|
104
|
-
pub fn builder() -> ConfigBuilder {
|
|
105
|
-
ConfigBuilder::default()
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
impl ConfigBuilder {
|
|
110
|
-
// Return boxed to avoid large move
|
|
111
|
-
pub fn build(self) -> Box<LargeConfig> {
|
|
112
|
-
Box::new(LargeConfig {
|
|
113
|
-
// ... fields from builder
|
|
114
|
-
})
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
## Profile First
|
|
120
|
-
|
|
121
|
-
Don't prematurely optimize. Use tools to identify if moves are actually a bottleneck:
|
|
122
|
-
|
|
123
|
-
```rust
|
|
124
|
-
// Check type sizes
|
|
125
|
-
println!("Size of GameState: {}", std::mem::size_of::<GameState>());
|
|
126
|
-
|
|
127
|
-
// Profile with cargo flamegraph or perf to find hot memcpys
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
## See Also
|
|
131
|
-
|
|
132
|
-
- [own-copy-small](./own-copy-small.md) - Cheap types should be Copy
|
|
133
|
-
- [mem-box-large-variant](./mem-box-large-variant.md) - Boxing enum variants
|
|
134
|
-
- [perf-profile-first](./perf-profile-first.md) - Measure before optimizing
|