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,168 +0,0 @@
|
|
|
1
|
-
# mem-arena-allocator
|
|
2
|
-
|
|
3
|
-
> Use arena allocators for batch allocations
|
|
4
|
-
|
|
5
|
-
## Why It Matters
|
|
6
|
-
|
|
7
|
-
Arena allocators (bump allocators) allocate memory from a contiguous region, making allocation extremely fast (just bump a pointer). All allocations are freed at once when the arena is dropped. Perfect for request-scoped or parse-tree allocations.
|
|
8
|
-
|
|
9
|
-
## Bad
|
|
10
|
-
|
|
11
|
-
```rust
|
|
12
|
-
// Many small allocations during parsing
|
|
13
|
-
fn parse(input: &str) -> Vec<Node> {
|
|
14
|
-
let mut nodes = Vec::new();
|
|
15
|
-
for token in tokenize(input) {
|
|
16
|
-
nodes.push(Box::new(Node::new(token))); // Heap alloc per node!
|
|
17
|
-
}
|
|
18
|
-
nodes
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
// Per-request allocations add up
|
|
22
|
-
fn handle_request(req: Request) -> Response {
|
|
23
|
-
let headers = parse_headers(&req); // Allocates
|
|
24
|
-
let body = parse_body(&req); // Allocates
|
|
25
|
-
let response = generate_response(); // Allocates
|
|
26
|
-
// All freed individually at end
|
|
27
|
-
response
|
|
28
|
-
}
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
## Good
|
|
32
|
-
|
|
33
|
-
```rust
|
|
34
|
-
use bumpalo::Bump;
|
|
35
|
-
|
|
36
|
-
// All nodes allocated from same arena
|
|
37
|
-
fn parse<'a>(input: &str, arena: &'a Bump) -> Vec<&'a Node> {
|
|
38
|
-
let mut nodes = Vec::new();
|
|
39
|
-
for token in tokenize(input) {
|
|
40
|
-
let node = arena.alloc(Node::new(token)); // Fast bump!
|
|
41
|
-
nodes.push(node);
|
|
42
|
-
}
|
|
43
|
-
nodes
|
|
44
|
-
} // Arena freed all at once
|
|
45
|
-
|
|
46
|
-
// Per-request arena
|
|
47
|
-
fn handle_request(req: Request) -> Response {
|
|
48
|
-
let arena = Bump::new();
|
|
49
|
-
|
|
50
|
-
let headers = parse_headers(&req, &arena);
|
|
51
|
-
let body = parse_body(&req, &arena);
|
|
52
|
-
let response = generate_response(&arena);
|
|
53
|
-
|
|
54
|
-
// Convert to owned response before arena drops
|
|
55
|
-
response.to_owned()
|
|
56
|
-
} // All request memory freed instantly
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
## Thread-Local Scratch Arena Pattern
|
|
60
|
-
|
|
61
|
-
```rust
|
|
62
|
-
use bumpalo::Bump;
|
|
63
|
-
use std::cell::RefCell;
|
|
64
|
-
|
|
65
|
-
thread_local! {
|
|
66
|
-
static SCRATCH: RefCell<Bump> = RefCell::new(Bump::with_capacity(4 * 1024));
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
fn with_scratch<T>(f: impl FnOnce(&Bump) -> T) -> T {
|
|
70
|
-
SCRATCH.with(|scratch| {
|
|
71
|
-
let arena = scratch.borrow();
|
|
72
|
-
let result = f(&arena);
|
|
73
|
-
result
|
|
74
|
-
})
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
fn reset_scratch() {
|
|
78
|
-
SCRATCH.with(|scratch| {
|
|
79
|
-
scratch.borrow_mut().reset();
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// Usage
|
|
84
|
-
fn process_batch(items: &[Item]) -> Vec<Output> {
|
|
85
|
-
with_scratch(|arena| {
|
|
86
|
-
let temp_data: Vec<&TempData> = items
|
|
87
|
-
.iter()
|
|
88
|
-
.map(|item| arena.alloc(compute_temp(item)))
|
|
89
|
-
.collect();
|
|
90
|
-
|
|
91
|
-
// Use temp_data...
|
|
92
|
-
let result = finalize(&temp_data);
|
|
93
|
-
|
|
94
|
-
reset_scratch(); // Reuse arena memory
|
|
95
|
-
result
|
|
96
|
-
})
|
|
97
|
-
}
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
## Evidence from ROC Compiler
|
|
101
|
-
|
|
102
|
-
```rust
|
|
103
|
-
// https://github.com/roc-lang/roc/blob/main/crates/compiler/solve/src/to_var.rs
|
|
104
|
-
std::thread_local! {
|
|
105
|
-
static SCRATCHPAD: RefCell<Option<bumpalo::Bump>> =
|
|
106
|
-
RefCell::new(Some(bumpalo::Bump::with_capacity(4 * 1024)));
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
fn take_scratchpad() -> bumpalo::Bump {
|
|
110
|
-
SCRATCHPAD.with(|f| f.take().unwrap())
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
fn put_scratchpad(scratchpad: bumpalo::Bump) {
|
|
114
|
-
SCRATCHPAD.with(|f| {
|
|
115
|
-
f.replace(Some(scratchpad));
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
## Bumpalo Collections
|
|
121
|
-
|
|
122
|
-
```rust
|
|
123
|
-
use bumpalo::Bump;
|
|
124
|
-
use bumpalo::collections::{Vec, String};
|
|
125
|
-
|
|
126
|
-
fn process<'a>(arena: &'a Bump, input: &str) -> Vec<'a, String<'a>> {
|
|
127
|
-
let mut results = Vec::new_in(arena);
|
|
128
|
-
|
|
129
|
-
for word in input.split_whitespace() {
|
|
130
|
-
let mut s = String::new_in(arena);
|
|
131
|
-
s.push_str(word);
|
|
132
|
-
s.push_str("_processed");
|
|
133
|
-
results.push(s);
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
results // All allocated in arena
|
|
137
|
-
}
|
|
138
|
-
```
|
|
139
|
-
|
|
140
|
-
## When to Use Arenas
|
|
141
|
-
|
|
142
|
-
| Situation | Use Arena? |
|
|
143
|
-
|-----------|-----------|
|
|
144
|
-
| Parsing (AST nodes) | Yes |
|
|
145
|
-
| Request handling | Yes |
|
|
146
|
-
| Batch processing | Yes |
|
|
147
|
-
| Long-lived data | No |
|
|
148
|
-
| Data escaping scope | No (or copy out) |
|
|
149
|
-
| Simple programs | Overkill |
|
|
150
|
-
|
|
151
|
-
## Performance Impact
|
|
152
|
-
|
|
153
|
-
```rust
|
|
154
|
-
// Benchmarks from production systems:
|
|
155
|
-
// - Individual allocations: ~25-50ns each
|
|
156
|
-
// - Arena bump: ~1-2ns each (20-50x faster)
|
|
157
|
-
// - Arena reset: O(1) regardless of allocation count
|
|
158
|
-
|
|
159
|
-
// Memory overhead:
|
|
160
|
-
// - Arena wastes some memory (unused capacity)
|
|
161
|
-
// - But eliminates per-allocation metadata overhead
|
|
162
|
-
```
|
|
163
|
-
|
|
164
|
-
## See Also
|
|
165
|
-
|
|
166
|
-
- [mem-with-capacity](mem-with-capacity.md) - Pre-allocate when size is known
|
|
167
|
-
- [mem-reuse-collections](mem-reuse-collections.md) - Reuse collections with clear()
|
|
168
|
-
- [opt-profile-first](perf-profile-first.md) - Profile to verify benefit
|
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
# mem-arrayvec
|
|
2
|
-
|
|
3
|
-
> Use `ArrayVec<T, N>` for fixed-capacity collections that never heap-allocate
|
|
4
|
-
|
|
5
|
-
## Why It Matters
|
|
6
|
-
|
|
7
|
-
`ArrayVec` from the `arrayvec` crate provides Vec-like API with a compile-time maximum capacity, storing all elements inline on the stack. Unlike `SmallVec` which can spill to heap, `ArrayVec` guarantees no heap allocation—if you exceed capacity, it returns an error or panics. This is ideal for embedded systems, real-time code, or when you have a hard upper bound.
|
|
8
|
-
|
|
9
|
-
## Bad
|
|
10
|
-
|
|
11
|
-
```rust
|
|
12
|
-
// Vec always heap-allocates, even for small collections
|
|
13
|
-
fn parse_options(input: &str) -> Vec<Option> {
|
|
14
|
-
let mut options = Vec::new(); // Heap allocation
|
|
15
|
-
for part in input.split(',').take(8) { // Know we never exceed 8
|
|
16
|
-
options.push(parse_option(part));
|
|
17
|
-
}
|
|
18
|
-
options
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
// Or SmallVec when you truly can't exceed capacity
|
|
22
|
-
use smallvec::SmallVec;
|
|
23
|
-
fn get_flags() -> SmallVec<[Flag; 4]> {
|
|
24
|
-
// SmallVec CAN heap-allocate if pushed beyond 4
|
|
25
|
-
// That might be unexpected in no-alloc contexts
|
|
26
|
-
}
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
## Good
|
|
30
|
-
|
|
31
|
-
```rust
|
|
32
|
-
use arrayvec::ArrayVec;
|
|
33
|
-
|
|
34
|
-
// Guaranteed no heap allocation
|
|
35
|
-
fn parse_options(input: &str) -> ArrayVec<Option, 8> {
|
|
36
|
-
let mut options = ArrayVec::new();
|
|
37
|
-
for part in input.split(',') {
|
|
38
|
-
if options.try_push(parse_option(part)).is_err() {
|
|
39
|
-
break; // Capacity reached, stop
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
options
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// For embedded/no_std contexts
|
|
46
|
-
#[no_std]
|
|
47
|
-
fn collect_readings() -> ArrayVec<SensorReading, 16> {
|
|
48
|
-
let mut readings = ArrayVec::new();
|
|
49
|
-
for sensor in SENSORS.iter() {
|
|
50
|
-
readings.push(sensor.read()); // Panics if > 16
|
|
51
|
-
}
|
|
52
|
-
readings
|
|
53
|
-
}
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
## ArrayVec vs SmallVec vs Vec
|
|
57
|
-
|
|
58
|
-
| Type | Stack | Heap | Use When |
|
|
59
|
-
|------|-------|------|----------|
|
|
60
|
-
| `Vec<T>` | Never | Always | Unknown size, may grow indefinitely |
|
|
61
|
-
| `SmallVec<[T; N]>` | Up to N | Beyond N | Usually small, occasionally large |
|
|
62
|
-
| `ArrayVec<T, N>` | Always | Never | Hard limit, no heap allowed |
|
|
63
|
-
|
|
64
|
-
## API Patterns
|
|
65
|
-
|
|
66
|
-
```rust
|
|
67
|
-
use arrayvec::ArrayVec;
|
|
68
|
-
|
|
69
|
-
let mut arr: ArrayVec<i32, 4> = ArrayVec::new();
|
|
70
|
-
|
|
71
|
-
// Push with potential panic (like Vec)
|
|
72
|
-
arr.push(1);
|
|
73
|
-
arr.push(2);
|
|
74
|
-
|
|
75
|
-
// Safe push - returns Err if full
|
|
76
|
-
match arr.try_push(3) {
|
|
77
|
-
Ok(()) => println!("Added"),
|
|
78
|
-
Err(err) => println!("Full, couldn't add {}", err.element()),
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// Check capacity
|
|
82
|
-
assert!(arr.len() < arr.capacity());
|
|
83
|
-
|
|
84
|
-
// Remaining capacity
|
|
85
|
-
let remaining = arr.remaining_capacity();
|
|
86
|
-
|
|
87
|
-
// Is it full?
|
|
88
|
-
if arr.is_full() {
|
|
89
|
-
arr.pop();
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// From iterator with limit
|
|
93
|
-
let arr: ArrayVec<_, 10> = (0..100)
|
|
94
|
-
.filter(|x| x % 2 == 0)
|
|
95
|
-
.take(10) // Important: don't exceed capacity
|
|
96
|
-
.collect();
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
## ArrayString for Stack Strings
|
|
100
|
-
|
|
101
|
-
```rust
|
|
102
|
-
use arrayvec::ArrayString;
|
|
103
|
-
|
|
104
|
-
// Stack-allocated string with max capacity
|
|
105
|
-
let mut s: ArrayString<64> = ArrayString::new();
|
|
106
|
-
s.push_str("Hello, ");
|
|
107
|
-
s.push_str("world!");
|
|
108
|
-
|
|
109
|
-
// No heap allocation for small strings
|
|
110
|
-
fn format_code(code: u32) -> ArrayString<16> {
|
|
111
|
-
let mut s = ArrayString::new();
|
|
112
|
-
write!(&mut s, "CODE-{:04}", code).unwrap();
|
|
113
|
-
s
|
|
114
|
-
}
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
## When NOT to Use ArrayVec
|
|
118
|
-
|
|
119
|
-
```rust
|
|
120
|
-
// ❌ When size varies widely
|
|
121
|
-
fn parse_json_array(json: &str) -> ArrayVec<Value, ???> {
|
|
122
|
-
// What capacity? JSON arrays can be any size
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
// ❌ When capacity is very large
|
|
126
|
-
let big: ArrayVec<u8, 1_000_000> = ArrayVec::new(); // 1MB on stack = bad
|
|
127
|
-
|
|
128
|
-
// ✅ Use SmallVec or Vec instead for these cases
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
## Cargo.toml
|
|
132
|
-
|
|
133
|
-
```toml
|
|
134
|
-
[dependencies]
|
|
135
|
-
arrayvec = "0.7"
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
## See Also
|
|
139
|
-
|
|
140
|
-
- [mem-smallvec](./mem-smallvec.md) - When heap fallback is acceptable
|
|
141
|
-
- [mem-with-capacity](./mem-with-capacity.md) - Pre-allocating Vec capacity
|
|
142
|
-
- [own-move-large](./own-move-large.md) - Large stack types considerations
|
|
@@ -1,168 +0,0 @@
|
|
|
1
|
-
# mem-assert-type-size
|
|
2
|
-
|
|
3
|
-
> Use static assertions to guard against accidental type size growth
|
|
4
|
-
|
|
5
|
-
## Why It Matters
|
|
6
|
-
|
|
7
|
-
Adding a field to a frequently-instantiated struct can silently bloat memory usage. Static size assertions catch this at compile time, making size changes intentional rather than accidental. This is especially important for types stored in large collections or passed frequently by value.
|
|
8
|
-
|
|
9
|
-
## Bad
|
|
10
|
-
|
|
11
|
-
```rust
|
|
12
|
-
struct Event {
|
|
13
|
-
timestamp: u64,
|
|
14
|
-
kind: EventKind,
|
|
15
|
-
payload: [u8; 32],
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
// Later, someone adds a field without realizing the impact
|
|
19
|
-
struct Event {
|
|
20
|
-
timestamp: u64,
|
|
21
|
-
kind: EventKind,
|
|
22
|
-
payload: [u8; 32],
|
|
23
|
-
metadata: String, // Silently adds 24 bytes!
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// 10 million events now use 240MB more memory
|
|
27
|
-
// No warning, no review trigger
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
## Good
|
|
31
|
-
|
|
32
|
-
```rust
|
|
33
|
-
struct Event {
|
|
34
|
-
timestamp: u64,
|
|
35
|
-
kind: EventKind,
|
|
36
|
-
payload: [u8; 32],
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// Static assertion - breaks compile if size changes
|
|
40
|
-
const _: () = assert!(std::mem::size_of::<Event>() == 48);
|
|
41
|
-
|
|
42
|
-
// Or with static_assertions crate
|
|
43
|
-
use static_assertions::assert_eq_size;
|
|
44
|
-
assert_eq_size!(Event, [u8; 48]);
|
|
45
|
-
|
|
46
|
-
// Now adding metadata triggers compile error:
|
|
47
|
-
// error: assertion failed: std::mem::size_of::<Event>() == 48
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
## static_assertions Crate
|
|
51
|
-
|
|
52
|
-
```rust
|
|
53
|
-
use static_assertions::{assert_eq_size, const_assert};
|
|
54
|
-
|
|
55
|
-
struct Critical {
|
|
56
|
-
id: u64,
|
|
57
|
-
flags: u32,
|
|
58
|
-
data: [u8; 16],
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// Exact size assertion
|
|
62
|
-
assert_eq_size!(Critical, [u8; 32]);
|
|
63
|
-
|
|
64
|
-
// Maximum size assertion
|
|
65
|
-
const_assert!(std::mem::size_of::<Critical>() <= 64);
|
|
66
|
-
|
|
67
|
-
// Alignment assertion
|
|
68
|
-
const_assert!(std::mem::align_of::<Critical>() == 8);
|
|
69
|
-
|
|
70
|
-
// Compare sizes
|
|
71
|
-
assert_eq_size!(Critical, [u64; 4]);
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
## Built-in Const Assertions
|
|
75
|
-
|
|
76
|
-
```rust
|
|
77
|
-
// No external crate needed (Rust 1.57+)
|
|
78
|
-
struct Packet {
|
|
79
|
-
header: u32,
|
|
80
|
-
payload: [u8; 60],
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
const _: () = assert!(
|
|
84
|
-
std::mem::size_of::<Packet>() == 64,
|
|
85
|
-
"Packet must be exactly 64 bytes for protocol compliance"
|
|
86
|
-
);
|
|
87
|
-
|
|
88
|
-
// Compile error shows custom message if assertion fails
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
## Documenting Size Constraints
|
|
92
|
-
|
|
93
|
-
```rust
|
|
94
|
-
/// Network protocol packet header.
|
|
95
|
-
///
|
|
96
|
-
/// # Size
|
|
97
|
-
///
|
|
98
|
-
/// This struct is guaranteed to be exactly 32 bytes to match
|
|
99
|
-
/// the network protocol specification. Any changes to fields
|
|
100
|
-
/// must maintain this size constraint.
|
|
101
|
-
#[repr(C)] // Predictable layout for FFI
|
|
102
|
-
struct Header {
|
|
103
|
-
version: u16,
|
|
104
|
-
flags: u16,
|
|
105
|
-
length: u32,
|
|
106
|
-
checksum: u64,
|
|
107
|
-
reserved: [u8; 16],
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
const _: () = assert!(std::mem::size_of::<Header>() == 32);
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
## Testing Size Stability
|
|
114
|
-
|
|
115
|
-
```rust
|
|
116
|
-
#[cfg(test)]
|
|
117
|
-
mod tests {
|
|
118
|
-
use super::*;
|
|
119
|
-
|
|
120
|
-
#[test]
|
|
121
|
-
fn critical_types_have_expected_sizes() {
|
|
122
|
-
// Document expected sizes in tests too
|
|
123
|
-
assert_eq!(std::mem::size_of::<Event>(), 48);
|
|
124
|
-
assert_eq!(std::mem::size_of::<Message>(), 64);
|
|
125
|
-
assert_eq!(std::mem::size_of::<Header>(), 32);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
#[test]
|
|
129
|
-
fn cache_line_aligned() {
|
|
130
|
-
// Verify cache-friendly sizing
|
|
131
|
-
assert!(std::mem::size_of::<HotData>() <= 64);
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
```
|
|
135
|
-
|
|
136
|
-
## When to Assert
|
|
137
|
-
|
|
138
|
-
```rust
|
|
139
|
-
// ✅ Types stored in large collections
|
|
140
|
-
struct Node { /* ... */ }
|
|
141
|
-
const _: () = assert!(std::mem::size_of::<Node>() <= 64);
|
|
142
|
-
|
|
143
|
-
// ✅ Types used in FFI / binary protocols
|
|
144
|
-
#[repr(C)]
|
|
145
|
-
struct WireFormat { /* ... */ }
|
|
146
|
-
const _: () = assert!(std::mem::size_of::<WireFormat>() == 256);
|
|
147
|
-
|
|
148
|
-
// ✅ Performance-critical types
|
|
149
|
-
struct HotPath { /* ... */ }
|
|
150
|
-
const _: () = assert!(std::mem::size_of::<HotPath>() <= 128);
|
|
151
|
-
|
|
152
|
-
// ❌ Skip for rarely-instantiated types
|
|
153
|
-
struct AppConfig { /* many fields */ }
|
|
154
|
-
// Size doesn't matter, only one instance
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
## Cargo.toml
|
|
158
|
-
|
|
159
|
-
```toml
|
|
160
|
-
[dependencies]
|
|
161
|
-
static_assertions = "1.1"
|
|
162
|
-
```
|
|
163
|
-
|
|
164
|
-
## See Also
|
|
165
|
-
|
|
166
|
-
- [mem-smaller-integers](./mem-smaller-integers.md) - Choosing appropriate integer sizes
|
|
167
|
-
- [mem-box-large-variant](./mem-box-large-variant.md) - Managing enum variant sizes
|
|
168
|
-
- [opt-cache-friendly](./opt-cache-friendly.md) - Cache line considerations
|
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
# mem-avoid-format
|
|
2
|
-
|
|
3
|
-
> Avoid `format!()` when string literals work
|
|
4
|
-
|
|
5
|
-
## Why It Matters
|
|
6
|
-
|
|
7
|
-
`format!()` always allocates a new String, even for constant text. In hot paths, these allocations add up. Use string literals, `write!()`, or pre-allocated buffers instead.
|
|
8
|
-
|
|
9
|
-
## Bad
|
|
10
|
-
|
|
11
|
-
```rust
|
|
12
|
-
// Allocates every time, even for static text
|
|
13
|
-
fn get_error_message() -> String {
|
|
14
|
-
format!("An error occurred") // Unnecessary allocation!
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
// Allocates in a loop
|
|
18
|
-
for item in items {
|
|
19
|
-
log::info!("{}", format!("Processing item: {}", item)); // Double work!
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
// format! in hot path
|
|
23
|
-
fn classify(n: i32) -> String {
|
|
24
|
-
if n > 0 {
|
|
25
|
-
format!("positive") // Allocates!
|
|
26
|
-
} else if n < 0 {
|
|
27
|
-
format!("negative") // Allocates!
|
|
28
|
-
} else {
|
|
29
|
-
format!("zero") // Allocates!
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
## Good
|
|
35
|
-
|
|
36
|
-
```rust
|
|
37
|
-
// Return &'static str for constants
|
|
38
|
-
fn get_error_message() -> &'static str {
|
|
39
|
-
"An error occurred" // No allocation
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// Use format args directly
|
|
43
|
-
for item in items {
|
|
44
|
-
log::info!("Processing item: {}", item); // No intermediate String
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// Return Cow for mixed static/dynamic
|
|
48
|
-
use std::borrow::Cow;
|
|
49
|
-
|
|
50
|
-
fn classify(n: i32) -> Cow<'static, str> {
|
|
51
|
-
if n > 0 {
|
|
52
|
-
Cow::Borrowed("positive") // No allocation
|
|
53
|
-
} else if n < 0 {
|
|
54
|
-
Cow::Borrowed("negative") // No allocation
|
|
55
|
-
} else {
|
|
56
|
-
Cow::Borrowed("zero") // No allocation
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// Or just &'static str if always static
|
|
61
|
-
fn classify_str(n: i32) -> &'static str {
|
|
62
|
-
if n > 0 { "positive" }
|
|
63
|
-
else if n < 0 { "negative" }
|
|
64
|
-
else { "zero" }
|
|
65
|
-
}
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
## Use write!() for Output
|
|
69
|
-
|
|
70
|
-
```rust
|
|
71
|
-
use std::io::Write;
|
|
72
|
-
|
|
73
|
-
// Bad: Allocate then write
|
|
74
|
-
fn bad_log(writer: &mut impl Write, msg: &str, code: u32) {
|
|
75
|
-
let formatted = format!("[ERROR {}] {}", code, msg); // Allocation!
|
|
76
|
-
writer.write_all(formatted.as_bytes()).unwrap();
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
// Good: Write directly
|
|
80
|
-
fn good_log(writer: &mut impl Write, msg: &str, code: u32) {
|
|
81
|
-
write!(writer, "[ERROR {}] {}", code, msg).unwrap(); // No allocation!
|
|
82
|
-
}
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
## Pre-allocate for Multiple Appends
|
|
86
|
-
|
|
87
|
-
```rust
|
|
88
|
-
// Bad: Multiple allocations
|
|
89
|
-
fn build_message(parts: &[&str]) -> String {
|
|
90
|
-
let mut result = String::new();
|
|
91
|
-
for part in parts {
|
|
92
|
-
result = format!("{}{}\n", result, part); // Allocates each iteration!
|
|
93
|
-
}
|
|
94
|
-
result
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// Good: Pre-allocate
|
|
98
|
-
fn build_message(parts: &[&str]) -> String {
|
|
99
|
-
let total_len: usize = parts.iter().map(|p| p.len() + 1).sum();
|
|
100
|
-
let mut result = String::with_capacity(total_len);
|
|
101
|
-
for part in parts {
|
|
102
|
-
result.push_str(part);
|
|
103
|
-
result.push('\n');
|
|
104
|
-
}
|
|
105
|
-
result
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// Good: Use join
|
|
109
|
-
fn build_message(parts: &[&str]) -> String {
|
|
110
|
-
parts.join("\n")
|
|
111
|
-
}
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
## CompactString for Small Strings
|
|
115
|
-
|
|
116
|
-
```rust
|
|
117
|
-
use compact_str::CompactString;
|
|
118
|
-
|
|
119
|
-
// Stack-allocated for strings <= 24 bytes
|
|
120
|
-
fn format_code(code: u32) -> CompactString {
|
|
121
|
-
compact_str::format_compact!("ERR-{:04}", code)
|
|
122
|
-
// Stack-allocated if result is small enough
|
|
123
|
-
}
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
## When format!() Is Fine
|
|
127
|
-
|
|
128
|
-
```rust
|
|
129
|
-
// Rare/cold paths - clarity over micro-optimization
|
|
130
|
-
fn log_startup_message() {
|
|
131
|
-
println!("{}", format!("Starting {} v{}", APP_NAME, VERSION));
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// When you need an owned String anyway
|
|
135
|
-
fn create_user_greeting(name: &str) -> String {
|
|
136
|
-
format!("Hello, {}!", name) // Need owned String
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
// Error messages (already on error path)
|
|
140
|
-
return Err(format!("Invalid value: {}", value).into());
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
## See Also
|
|
144
|
-
|
|
145
|
-
- [mem-write-over-format](mem-write-over-format.md) - Use write!() instead of format!()
|
|
146
|
-
- [mem-with-capacity](mem-with-capacity.md) - Pre-allocate strings
|
|
147
|
-
- [own-cow-conditional](own-cow-conditional.md) - Use Cow for mixed static/dynamic
|