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,149 +0,0 @@
|
|
|
1
|
-
# mem-compact-string
|
|
2
|
-
|
|
3
|
-
> Use compact string types for memory-constrained string storage
|
|
4
|
-
|
|
5
|
-
## Why It Matters
|
|
6
|
-
|
|
7
|
-
Standard `String` is 24 bytes (pointer + length + capacity). For applications storing millions of short strings, this overhead dominates. Compact string libraries like `compact_str`, `smartstring`, or `ecow` store small strings inline (no heap allocation) and use optimized layouts for larger strings.
|
|
8
|
-
|
|
9
|
-
## Bad
|
|
10
|
-
|
|
11
|
-
```rust
|
|
12
|
-
struct User {
|
|
13
|
-
id: u64,
|
|
14
|
-
// Most usernames are < 24 chars, but String is always 24 bytes + heap
|
|
15
|
-
username: String,
|
|
16
|
-
email: String,
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
// 1 million users = 24 bytes * 2 * 1M = 48MB just for String metadata
|
|
20
|
-
// Plus all the heap allocations for actual content
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
## Good
|
|
24
|
-
|
|
25
|
-
```rust
|
|
26
|
-
use compact_str::CompactString;
|
|
27
|
-
|
|
28
|
-
struct User {
|
|
29
|
-
id: u64,
|
|
30
|
-
// CompactString: 24 bytes, but strings ≤ 24 chars are inline (no heap)
|
|
31
|
-
username: CompactString,
|
|
32
|
-
email: CompactString,
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// Most usernames fit inline = zero heap allocations
|
|
36
|
-
// Same memory footprint as String but way fewer allocations
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
## Compact String Libraries
|
|
40
|
-
|
|
41
|
-
### compact_str
|
|
42
|
-
|
|
43
|
-
```rust
|
|
44
|
-
use compact_str::CompactString;
|
|
45
|
-
|
|
46
|
-
// Inline storage for strings ≤ 24 bytes
|
|
47
|
-
let small: CompactString = "hello".into(); // No heap allocation
|
|
48
|
-
|
|
49
|
-
// Automatic heap fallback for larger strings
|
|
50
|
-
let large: CompactString = "x".repeat(100).into();
|
|
51
|
-
|
|
52
|
-
// String-like API
|
|
53
|
-
let mut s = CompactString::new("hello");
|
|
54
|
-
s.push_str(" world");
|
|
55
|
-
assert_eq!(s.as_str(), "hello world");
|
|
56
|
-
|
|
57
|
-
// Format macro
|
|
58
|
-
use compact_str::format_compact;
|
|
59
|
-
let s = format_compact!("value: {}", 42);
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
### smartstring
|
|
63
|
-
|
|
64
|
-
```rust
|
|
65
|
-
use smartstring::{SmartString, LazyCompact};
|
|
66
|
-
|
|
67
|
-
// Default is LazyCompact: 24 bytes inline capacity
|
|
68
|
-
let s: SmartString<LazyCompact> = "short string".into();
|
|
69
|
-
|
|
70
|
-
// Compact mode: 23 bytes inline on 64-bit
|
|
71
|
-
use smartstring::Compact;
|
|
72
|
-
let s: SmartString<Compact> = "hello".into();
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
### ecow (copy-on-write)
|
|
76
|
-
|
|
77
|
-
```rust
|
|
78
|
-
use ecow::EcoString;
|
|
79
|
-
|
|
80
|
-
// Clone is O(1) - shares underlying data
|
|
81
|
-
let s1: EcoString = "shared data".into();
|
|
82
|
-
let s2 = s1.clone(); // Cheap, shares allocation
|
|
83
|
-
|
|
84
|
-
// Copy-on-write: only allocates on mutation
|
|
85
|
-
let mut s3 = s1.clone();
|
|
86
|
-
s3.push_str(" modified"); // Now allocates
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
## Memory Comparison
|
|
90
|
-
|
|
91
|
-
```rust
|
|
92
|
-
use std::mem::size_of;
|
|
93
|
-
|
|
94
|
-
// All 24 bytes, but different inline capacities
|
|
95
|
-
assert_eq!(size_of::<String>(), 24);
|
|
96
|
-
assert_eq!(size_of::<compact_str::CompactString>(), 24);
|
|
97
|
-
assert_eq!(size_of::<smartstring::SmartString>(), 24);
|
|
98
|
-
assert_eq!(size_of::<ecow::EcoString>(), 16); // Even smaller!
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
## Inline Capacity
|
|
102
|
-
|
|
103
|
-
| Type | Size | Inline Capacity |
|
|
104
|
-
|------|------|-----------------|
|
|
105
|
-
| `String` | 24 | 0 (always heap) |
|
|
106
|
-
| `CompactString` | 24 | 24 bytes |
|
|
107
|
-
| `SmartString<LazyCompact>` | 24 | 23 bytes |
|
|
108
|
-
| `EcoString` | 16 | 15 bytes |
|
|
109
|
-
|
|
110
|
-
## When to Use
|
|
111
|
-
|
|
112
|
-
```rust
|
|
113
|
-
// ✅ Good: Many short strings in memory
|
|
114
|
-
struct Dictionary {
|
|
115
|
-
words: Vec<CompactString>, // Millions of short words
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
// ✅ Good: Frequently cloned strings
|
|
119
|
-
struct Template {
|
|
120
|
-
parts: Vec<EcoString>, // O(1) clone
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
// ❌ Don't: Hot path string manipulation
|
|
124
|
-
fn transform(s: &str) -> String {
|
|
125
|
-
// Standard String is optimized for manipulation
|
|
126
|
-
s.to_uppercase()
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// ❌ Don't: API boundaries (prefer &str or String for interop)
|
|
130
|
-
pub fn public_api(input: CompactString) { } // Forces dependency
|
|
131
|
-
pub fn public_api(input: impl Into<String>) { } // Better
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
## Cargo.toml
|
|
135
|
-
|
|
136
|
-
```toml
|
|
137
|
-
[dependencies]
|
|
138
|
-
compact_str = "0.7"
|
|
139
|
-
# or
|
|
140
|
-
smartstring = "1.0"
|
|
141
|
-
# or
|
|
142
|
-
ecow = "0.2"
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
## See Also
|
|
146
|
-
|
|
147
|
-
- [mem-boxed-slice](./mem-boxed-slice.md) - Box<str> for immutable strings
|
|
148
|
-
- [own-cow-conditional](./own-cow-conditional.md) - Cow<str> for borrow-or-own
|
|
149
|
-
- [mem-smallvec](./mem-smallvec.md) - Similar concept for Vec
|
|
@@ -1,174 +0,0 @@
|
|
|
1
|
-
# mem-reuse-collections
|
|
2
|
-
|
|
3
|
-
> Clear and reuse collections instead of creating new ones in loops
|
|
4
|
-
|
|
5
|
-
## Why It Matters
|
|
6
|
-
|
|
7
|
-
Creating new `Vec`, `String`, or `HashMap` instances in hot loops generates significant allocator pressure. Clearing a collection and reusing it keeps the existing capacity, avoiding repeated allocation/deallocation cycles. This is especially impactful for frequently-executed code paths.
|
|
8
|
-
|
|
9
|
-
## Bad
|
|
10
|
-
|
|
11
|
-
```rust
|
|
12
|
-
fn process_batches(batches: &[Batch]) -> Vec<Result> {
|
|
13
|
-
let mut results = Vec::new();
|
|
14
|
-
|
|
15
|
-
for batch in batches {
|
|
16
|
-
let mut temp = Vec::new(); // Allocates every iteration
|
|
17
|
-
|
|
18
|
-
for item in &batch.items {
|
|
19
|
-
temp.push(transform(item));
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
results.push(aggregate(&temp));
|
|
23
|
-
// temp dropped here, deallocation
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
results
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
fn format_lines(items: &[Item]) -> String {
|
|
30
|
-
let mut output = String::new();
|
|
31
|
-
|
|
32
|
-
for item in items {
|
|
33
|
-
let line = format!("{}: {}", item.name, item.value); // Allocates
|
|
34
|
-
output.push_str(&line);
|
|
35
|
-
output.push('\n');
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
output
|
|
39
|
-
}
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
## Good
|
|
43
|
-
|
|
44
|
-
```rust
|
|
45
|
-
fn process_batches(batches: &[Batch]) -> Vec<Result> {
|
|
46
|
-
let mut results = Vec::with_capacity(batches.len());
|
|
47
|
-
let mut temp = Vec::new(); // Allocate once outside loop
|
|
48
|
-
|
|
49
|
-
for batch in batches {
|
|
50
|
-
temp.clear(); // Reuse allocation, just reset length
|
|
51
|
-
|
|
52
|
-
for item in &batch.items {
|
|
53
|
-
temp.push(transform(item));
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
results.push(aggregate(&temp));
|
|
57
|
-
// temp keeps its capacity for next iteration
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
results
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
fn format_lines(items: &[Item]) -> String {
|
|
64
|
-
use std::fmt::Write;
|
|
65
|
-
|
|
66
|
-
let mut output = String::new();
|
|
67
|
-
let mut line = String::new(); // Reusable buffer
|
|
68
|
-
|
|
69
|
-
for item in items {
|
|
70
|
-
line.clear();
|
|
71
|
-
write!(&mut line, "{}: {}", item.name, item.value).unwrap();
|
|
72
|
-
output.push_str(&line);
|
|
73
|
-
output.push('\n');
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
output
|
|
77
|
-
}
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
## Clear vs Drain vs New
|
|
81
|
-
|
|
82
|
-
```rust
|
|
83
|
-
let mut vec = vec![1, 2, 3, 4, 5];
|
|
84
|
-
|
|
85
|
-
// clear(): keeps capacity, O(n) for Drop types
|
|
86
|
-
vec.clear();
|
|
87
|
-
assert_eq!(vec.len(), 0);
|
|
88
|
-
assert!(vec.capacity() >= 5);
|
|
89
|
-
|
|
90
|
-
// drain(): returns iterator, clears after iteration
|
|
91
|
-
let drained: Vec<_> = vec.drain(..).collect();
|
|
92
|
-
|
|
93
|
-
// truncate(): keeps first n elements
|
|
94
|
-
vec.truncate(2);
|
|
95
|
-
|
|
96
|
-
// Creating new: loses all capacity
|
|
97
|
-
vec = Vec::new(); // Capacity gone
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
## HashMap Reuse
|
|
101
|
-
|
|
102
|
-
```rust
|
|
103
|
-
use std::collections::HashMap;
|
|
104
|
-
|
|
105
|
-
fn count_words_per_line(lines: &[&str]) -> Vec<HashMap<String, usize>> {
|
|
106
|
-
let mut results = Vec::with_capacity(lines.len());
|
|
107
|
-
let mut counts = HashMap::new(); // Reuse across iterations
|
|
108
|
-
|
|
109
|
-
for line in lines {
|
|
110
|
-
counts.clear(); // Keeps bucket allocation
|
|
111
|
-
|
|
112
|
-
for word in line.split_whitespace() {
|
|
113
|
-
*counts.entry(word.to_string()).or_insert(0) += 1;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
results.push(counts.clone());
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
results
|
|
120
|
-
}
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
## BufWriter Pattern
|
|
124
|
-
|
|
125
|
-
```rust
|
|
126
|
-
use std::io::{BufWriter, Write};
|
|
127
|
-
|
|
128
|
-
fn write_many_records(records: &[Record], mut output: impl Write) -> std::io::Result<()> {
|
|
129
|
-
// BufWriter reuses its internal buffer
|
|
130
|
-
let mut writer = BufWriter::with_capacity(8192, &mut output);
|
|
131
|
-
let mut line = String::with_capacity(256); // Reusable formatting buffer
|
|
132
|
-
|
|
133
|
-
for record in records {
|
|
134
|
-
line.clear();
|
|
135
|
-
format_record(record, &mut line);
|
|
136
|
-
writer.write_all(line.as_bytes())?;
|
|
137
|
-
writer.write_all(b"\n")?;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
writer.flush()
|
|
141
|
-
}
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
## When to Create Fresh
|
|
145
|
-
|
|
146
|
-
```rust
|
|
147
|
-
// When ownership transfer is needed
|
|
148
|
-
fn produce_results() -> Vec<Vec<Item>> {
|
|
149
|
-
let mut results = Vec::new();
|
|
150
|
-
|
|
151
|
-
for batch in batches {
|
|
152
|
-
let processed: Vec<Item> = batch.process(); // Ownership transferred
|
|
153
|
-
results.push(processed); // Moved into results
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
results // Each inner Vec is independent
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
// When thread safety requires it
|
|
160
|
-
std::thread::scope(|s| {
|
|
161
|
-
for _ in 0..4 {
|
|
162
|
-
s.spawn(|| {
|
|
163
|
-
let local_buffer = Vec::new(); // Thread-local, can't share
|
|
164
|
-
// ...
|
|
165
|
-
});
|
|
166
|
-
}
|
|
167
|
-
});
|
|
168
|
-
```
|
|
169
|
-
|
|
170
|
-
## See Also
|
|
171
|
-
|
|
172
|
-
- [mem-with-capacity](./mem-with-capacity.md) - Pre-allocating capacity
|
|
173
|
-
- [mem-clone-from](./mem-clone-from.md) - Reusing allocations when cloning
|
|
174
|
-
- [mem-write-over-format](./mem-write-over-format.md) - Avoiding format! allocations
|
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
# mem-smaller-integers
|
|
2
|
-
|
|
3
|
-
> Use appropriately-sized integers to reduce memory footprint
|
|
4
|
-
|
|
5
|
-
## Why It Matters
|
|
6
|
-
|
|
7
|
-
Using `i64` when `i16` suffices wastes 6 bytes per value. In arrays, vectors, and structs with millions of instances, this waste compounds dramatically. Choosing the smallest integer type that fits your domain reduces memory usage and improves cache utilization.
|
|
8
|
-
|
|
9
|
-
## Bad
|
|
10
|
-
|
|
11
|
-
```rust
|
|
12
|
-
struct Pixel {
|
|
13
|
-
r: u64, // Color channels 0-255 = 8 bits needed
|
|
14
|
-
g: u64, // Using 64 bits = 8x waste
|
|
15
|
-
b: u64,
|
|
16
|
-
a: u64,
|
|
17
|
-
}
|
|
18
|
-
// Size: 32 bytes per pixel
|
|
19
|
-
|
|
20
|
-
struct HttpStatus {
|
|
21
|
-
code: i32, // HTTP codes 100-599 = 10 bits needed
|
|
22
|
-
version: i32, // HTTP 1.0, 1.1, 2, 3 = 2 bits needed
|
|
23
|
-
}
|
|
24
|
-
// Size: 8 bytes per status
|
|
25
|
-
|
|
26
|
-
struct GeoPoint {
|
|
27
|
-
lat: f64, // -90 to 90
|
|
28
|
-
lon: f64, // -180 to 180
|
|
29
|
-
}
|
|
30
|
-
// Often f32 precision is sufficient for display
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
## Good
|
|
34
|
-
|
|
35
|
-
```rust
|
|
36
|
-
struct Pixel {
|
|
37
|
-
r: u8,
|
|
38
|
-
g: u8,
|
|
39
|
-
b: u8,
|
|
40
|
-
a: u8,
|
|
41
|
-
}
|
|
42
|
-
// Size: 4 bytes per pixel (8x smaller!)
|
|
43
|
-
|
|
44
|
-
struct HttpStatus {
|
|
45
|
-
code: u16, // 100-599 fits in u16
|
|
46
|
-
version: u8, // 1, 2, 3 fits in u8
|
|
47
|
-
}
|
|
48
|
-
// Size: 3 bytes (+ 1 padding = 4 bytes)
|
|
49
|
-
|
|
50
|
-
struct GeoPoint {
|
|
51
|
-
lat: f32, // ~7 decimal digits precision
|
|
52
|
-
lon: f32, // Sufficient for most geo applications
|
|
53
|
-
}
|
|
54
|
-
// Size: 8 bytes vs 16 bytes
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
## Integer Size Reference
|
|
58
|
-
|
|
59
|
-
| Type | Range | Use For |
|
|
60
|
-
|------|-------|---------|
|
|
61
|
-
| `u8` | 0 to 255 | Bytes, small counts, flags |
|
|
62
|
-
| `i8` | -128 to 127 | Small signed values |
|
|
63
|
-
| `u16` | 0 to 65,535 | Port numbers, small indices |
|
|
64
|
-
| `i16` | -32,768 to 32,767 | Audio samples |
|
|
65
|
-
| `u32` | 0 to 4 billion | Array indices, timestamps (seconds) |
|
|
66
|
-
| `i32` | ±2 billion | General integers, file offsets |
|
|
67
|
-
| `u64` | 0 to 18 quintillion | Large counts, nanosecond timestamps |
|
|
68
|
-
| `usize` | Platform-dependent | Array indexing (required by Rust) |
|
|
69
|
-
|
|
70
|
-
## Struct Packing
|
|
71
|
-
|
|
72
|
-
```rust
|
|
73
|
-
use std::mem::size_of;
|
|
74
|
-
|
|
75
|
-
// Poor ordering - 24 bytes due to padding
|
|
76
|
-
struct Wasteful {
|
|
77
|
-
a: u8, // 1 byte + 7 padding
|
|
78
|
-
b: u64, // 8 bytes
|
|
79
|
-
c: u8, // 1 byte + 7 padding
|
|
80
|
-
}
|
|
81
|
-
assert_eq!(size_of::<Wasteful>(), 24);
|
|
82
|
-
|
|
83
|
-
// Better ordering - 16 bytes
|
|
84
|
-
struct Efficient {
|
|
85
|
-
b: u64, // 8 bytes (aligned)
|
|
86
|
-
a: u8, // 1 byte
|
|
87
|
-
c: u8, // 1 byte + 6 padding
|
|
88
|
-
}
|
|
89
|
-
assert_eq!(size_of::<Efficient>(), 16);
|
|
90
|
-
|
|
91
|
-
// Even better with smaller types - 10 bytes
|
|
92
|
-
struct Compact {
|
|
93
|
-
b: u32, // 4 bytes (if u32 suffices)
|
|
94
|
-
a: u8, // 1 byte
|
|
95
|
-
c: u8, // 1 byte
|
|
96
|
-
}
|
|
97
|
-
assert_eq!(size_of::<Compact>(), 8); // With padding
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
## Conversion Safety
|
|
101
|
-
|
|
102
|
-
```rust
|
|
103
|
-
// Safe: always succeeds (widening)
|
|
104
|
-
let small: u8 = 42;
|
|
105
|
-
let big: u32 = small.into();
|
|
106
|
-
|
|
107
|
-
// Fallible: may overflow (narrowing)
|
|
108
|
-
let big: u32 = 1000;
|
|
109
|
-
let small: u8 = big.try_into().expect("value out of range");
|
|
110
|
-
|
|
111
|
-
// Or use checked conversion
|
|
112
|
-
if let Ok(small) = u8::try_from(big) {
|
|
113
|
-
use_small(small);
|
|
114
|
-
} else {
|
|
115
|
-
handle_overflow();
|
|
116
|
-
}
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
## Bitflags for Boolean Sets
|
|
120
|
-
|
|
121
|
-
```rust
|
|
122
|
-
use bitflags::bitflags;
|
|
123
|
-
|
|
124
|
-
// Instead of 8 separate bool fields (8 bytes minimum)
|
|
125
|
-
bitflags! {
|
|
126
|
-
struct Permissions: u8 {
|
|
127
|
-
const READ = 0b0000_0001;
|
|
128
|
-
const WRITE = 0b0000_0010;
|
|
129
|
-
const EXECUTE = 0b0000_0100;
|
|
130
|
-
const DELETE = 0b0000_1000;
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
// All 8 flags in 1 byte!
|
|
134
|
-
|
|
135
|
-
let perms = Permissions::READ | Permissions::WRITE;
|
|
136
|
-
if perms.contains(Permissions::READ) {
|
|
137
|
-
// ...
|
|
138
|
-
}
|
|
139
|
-
```
|
|
140
|
-
|
|
141
|
-
## NonZero Types for Option Optimization
|
|
142
|
-
|
|
143
|
-
```rust
|
|
144
|
-
use std::num::NonZeroU64;
|
|
145
|
-
|
|
146
|
-
// Option<u64> = 16 bytes (no null pointer optimization)
|
|
147
|
-
assert_eq!(size_of::<Option<u64>>(), 16);
|
|
148
|
-
|
|
149
|
-
// Option<NonZeroU64> = 8 bytes (0 represents None)
|
|
150
|
-
assert_eq!(size_of::<Option<NonZeroU64>>(), 8);
|
|
151
|
-
|
|
152
|
-
let id: Option<NonZeroU64> = NonZeroU64::new(42);
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
## See Also
|
|
156
|
-
|
|
157
|
-
- [mem-box-large-variant](./mem-box-large-variant.md) - Optimizing enum sizes
|
|
158
|
-
- [mem-assert-type-size](./mem-assert-type-size.md) - Compile-time size checks
|
|
159
|
-
- [type-newtype-ids](./type-newtype-ids.md) - Type safety for integer IDs
|
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
# mem-smallvec
|
|
2
|
-
|
|
3
|
-
> Use `SmallVec` for usually-small collections
|
|
4
|
-
|
|
5
|
-
## Why It Matters
|
|
6
|
-
|
|
7
|
-
`SmallVec<[T; N]>` stores up to N elements inline (on the stack), only allocating on the heap when the size exceeds N. This eliminates heap allocations for the common case while still allowing growth when needed.
|
|
8
|
-
|
|
9
|
-
## Bad
|
|
10
|
-
|
|
11
|
-
```rust
|
|
12
|
-
// Always heap-allocates, even for 1-2 elements
|
|
13
|
-
fn get_path_components(path: &str) -> Vec<&str> {
|
|
14
|
-
path.split('/').collect() // Usually 2-4 components
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
// Always heap-allocates for error list
|
|
18
|
-
fn validate(input: &Input) -> Vec<ValidationError> {
|
|
19
|
-
let mut errors = Vec::new(); // Usually 0-3 errors
|
|
20
|
-
// validation logic...
|
|
21
|
-
errors
|
|
22
|
-
}
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
## Good
|
|
26
|
-
|
|
27
|
-
```rust
|
|
28
|
-
use smallvec::{smallvec, SmallVec};
|
|
29
|
-
|
|
30
|
-
// Stack-allocated for typical paths (1-8 components)
|
|
31
|
-
fn get_path_components(path: &str) -> SmallVec<[&str; 8]> {
|
|
32
|
-
path.split('/').collect()
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// Stack-allocated for typical error counts
|
|
36
|
-
fn validate(input: &Input) -> SmallVec<[ValidationError; 4]> {
|
|
37
|
-
let mut errors = SmallVec::new();
|
|
38
|
-
// validation logic...
|
|
39
|
-
errors
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// Using smallvec! macro
|
|
43
|
-
let v: SmallVec<[i32; 4]> = smallvec![1, 2, 3];
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
## Choosing Capacity N
|
|
47
|
-
|
|
48
|
-
```rust
|
|
49
|
-
// Measure your actual data distribution!
|
|
50
|
-
// Guidelines:
|
|
51
|
-
|
|
52
|
-
// Path components: 4-8 (most paths are shallow)
|
|
53
|
-
type PathParts<'a> = SmallVec<[&'a str; 8]>;
|
|
54
|
-
|
|
55
|
-
// Function arguments: 4-8 (most functions have few args)
|
|
56
|
-
type Args = SmallVec<[Arg; 8]>;
|
|
57
|
-
|
|
58
|
-
// AST children: 2-4 (binary ops, if/else, etc.)
|
|
59
|
-
type Children = SmallVec<[Node; 4]>;
|
|
60
|
-
|
|
61
|
-
// Error accumulation: 2-4 (most inputs have few errors)
|
|
62
|
-
type Errors = SmallVec<[Error; 4]>;
|
|
63
|
-
|
|
64
|
-
// Attribute lists: 4-8 (most items have few attributes)
|
|
65
|
-
type Attrs = SmallVec<[Attribute; 8]>;
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
## Evidence from rust-analyzer
|
|
69
|
-
|
|
70
|
-
```rust
|
|
71
|
-
// https://github.com/rust-lang/rust/blob/main/compiler/rustc_expand/src/base.rs
|
|
72
|
-
macro_rules! make_stmts_default {
|
|
73
|
-
($me:expr) => {
|
|
74
|
-
$me.make_expr().map(|e| {
|
|
75
|
-
smallvec![ast::Stmt {
|
|
76
|
-
id: ast::DUMMY_NODE_ID,
|
|
77
|
-
span: e.span,
|
|
78
|
-
kind: ast::StmtKind::Expr(e),
|
|
79
|
-
}]
|
|
80
|
-
})
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
## Trade-offs
|
|
86
|
-
|
|
87
|
-
```rust
|
|
88
|
-
// SmallVec is slightly larger than Vec
|
|
89
|
-
use std::mem::size_of;
|
|
90
|
-
// Vec<i32>: 24 bytes (ptr + len + cap)
|
|
91
|
-
// SmallVec<[i32; 4]>: 32 bytes (inline storage + len + discriminant)
|
|
92
|
-
|
|
93
|
-
// SmallVec has branching overhead on every operation
|
|
94
|
-
// (must check if inline or heap)
|
|
95
|
-
|
|
96
|
-
// Profile to verify benefit!
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
## When to Use SmallVec vs Alternatives
|
|
100
|
-
|
|
101
|
-
| Situation | Use |
|
|
102
|
-
|-----------|-----|
|
|
103
|
-
| Usually small, sometimes large | `SmallVec<[T; N]>` |
|
|
104
|
-
| Always small, fixed max | `ArrayVec<T, N>` |
|
|
105
|
-
| Rarely grows past initial | `Vec::with_capacity` |
|
|
106
|
-
| No `unsafe` allowed | `TinyVec` |
|
|
107
|
-
| Often empty | `ThinVec` |
|
|
108
|
-
|
|
109
|
-
## ArrayVec Alternative
|
|
110
|
-
|
|
111
|
-
```rust
|
|
112
|
-
use arrayvec::ArrayVec;
|
|
113
|
-
|
|
114
|
-
// Fixed maximum capacity, never heap allocates
|
|
115
|
-
// Panics if you exceed capacity
|
|
116
|
-
fn parse_rgb(s: &str) -> ArrayVec<u8, 3> {
|
|
117
|
-
let mut components = ArrayVec::new();
|
|
118
|
-
for part in s.split(',').take(3) {
|
|
119
|
-
components.push(part.parse().unwrap());
|
|
120
|
-
}
|
|
121
|
-
components
|
|
122
|
-
}
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
## TinyVec (No Unsafe)
|
|
126
|
-
|
|
127
|
-
```rust
|
|
128
|
-
use tinyvec::{tiny_vec, TinyVec};
|
|
129
|
-
|
|
130
|
-
// Same concept as SmallVec but 100% safe code
|
|
131
|
-
let v: TinyVec<[i32; 4]> = tiny_vec![1, 2, 3];
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
## See Also
|
|
135
|
-
|
|
136
|
-
- [mem-arrayvec](mem-arrayvec.md) - Use ArrayVec for fixed-max collections
|
|
137
|
-
- [mem-with-capacity](mem-with-capacity.md) - Pre-allocate when size is known
|
|
138
|
-
- [mem-thinvec](mem-thinvec.md) - Use ThinVec for often-empty vectors
|