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,142 +0,0 @@
|
|
|
1
|
-
# mem-thinvec
|
|
2
|
-
|
|
3
|
-
> Use `ThinVec<T>` for nullable collections with minimal overhead
|
|
4
|
-
|
|
5
|
-
## Why It Matters
|
|
6
|
-
|
|
7
|
-
Standard `Vec<T>` is 24 bytes even when empty. `ThinVec` from Mozilla's `thin_vec` crate uses a single pointer (8 bytes), storing length and capacity inline with the heap allocation. For Option<Vec<T>> patterns or structs with many optional vecs, this significantly reduces memory overhead.
|
|
8
|
-
|
|
9
|
-
## Bad
|
|
10
|
-
|
|
11
|
-
```rust
|
|
12
|
-
struct TreeNode {
|
|
13
|
-
value: i32,
|
|
14
|
-
// Each node pays 24 bytes for children, even leaves
|
|
15
|
-
children: Vec<TreeNode>, // Most nodes are leaves with empty Vec
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
// Or using Option<Vec<T>>
|
|
19
|
-
struct SparseData {
|
|
20
|
-
// Option<Vec> = 24 bytes (Vec is never null-pointer optimized)
|
|
21
|
-
tags: Option<Vec<String>>,
|
|
22
|
-
metadata: Option<Vec<Metadata>>,
|
|
23
|
-
// 48 bytes for usually-None fields
|
|
24
|
-
}
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
## Good
|
|
28
|
-
|
|
29
|
-
```rust
|
|
30
|
-
use thin_vec::ThinVec;
|
|
31
|
-
|
|
32
|
-
struct TreeNode {
|
|
33
|
-
value: i32,
|
|
34
|
-
// Empty ThinVec is just a null pointer - 8 bytes
|
|
35
|
-
children: ThinVec<TreeNode>,
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
struct SparseData {
|
|
39
|
-
// ThinVec empty = 8 bytes each
|
|
40
|
-
tags: ThinVec<String>,
|
|
41
|
-
metadata: ThinVec<Metadata>,
|
|
42
|
-
// 16 bytes vs 48 bytes
|
|
43
|
-
}
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
## Memory Layout
|
|
47
|
-
|
|
48
|
-
```rust
|
|
49
|
-
use std::mem::size_of;
|
|
50
|
-
|
|
51
|
-
// Standard Vec: always 24 bytes
|
|
52
|
-
assert_eq!(size_of::<Vec<u8>>(), 24);
|
|
53
|
-
assert_eq!(size_of::<Option<Vec<u8>>>(), 24); // No NPO benefit
|
|
54
|
-
|
|
55
|
-
// ThinVec: 8 bytes (one pointer)
|
|
56
|
-
use thin_vec::ThinVec;
|
|
57
|
-
assert_eq!(size_of::<ThinVec<u8>>(), 8);
|
|
58
|
-
assert_eq!(size_of::<Option<ThinVec<u8>>>(), 8); // Option is free!
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
## ThinVec vs Vec
|
|
62
|
-
|
|
63
|
-
| Feature | `Vec<T>` | `ThinVec<T>` |
|
|
64
|
-
|---------|----------|--------------|
|
|
65
|
-
| Size (empty) | 24 bytes | 8 bytes |
|
|
66
|
-
| Size (non-empty) | 24 bytes | 8 bytes (header on heap) |
|
|
67
|
-
| Option<T> optimization | No | Yes |
|
|
68
|
-
| Cache locality | Better (len/cap on stack) | Worse (len/cap on heap) |
|
|
69
|
-
| Iteration speed | Faster | Slightly slower |
|
|
70
|
-
| API compatibility | Full | Vec-like |
|
|
71
|
-
|
|
72
|
-
## When to Use ThinVec
|
|
73
|
-
|
|
74
|
-
```rust
|
|
75
|
-
// ✅ Good: Many instances, often empty
|
|
76
|
-
struct SparseGraph {
|
|
77
|
-
nodes: Vec<Node>,
|
|
78
|
-
// Most edges lists are empty or small
|
|
79
|
-
edges: Vec<ThinVec<EdgeId>>, // Saves 16 bytes per node
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// ✅ Good: Nullable collection field
|
|
83
|
-
struct Document {
|
|
84
|
-
content: String,
|
|
85
|
-
attachments: ThinVec<Attachment>, // Often empty
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
// ❌ Avoid: Hot loops, performance-critical iteration
|
|
89
|
-
fn process_hot_path(data: &ThinVec<Item>) {
|
|
90
|
-
// Every length check goes through pointer indirection
|
|
91
|
-
for item in data { // Vec would be faster here
|
|
92
|
-
process(item);
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// ❌ Avoid: Few instances
|
|
97
|
-
fn main() {
|
|
98
|
-
let single_vec: ThinVec<i32> = ThinVec::new();
|
|
99
|
-
// Saving 16 bytes once is meaningless
|
|
100
|
-
}
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
## API Compatibility
|
|
104
|
-
|
|
105
|
-
```rust
|
|
106
|
-
use thin_vec::{ThinVec, thin_vec};
|
|
107
|
-
|
|
108
|
-
// Constructor macro
|
|
109
|
-
let v: ThinVec<i32> = thin_vec![1, 2, 3];
|
|
110
|
-
|
|
111
|
-
// Familiar Vec-like API
|
|
112
|
-
let mut v = ThinVec::new();
|
|
113
|
-
v.push(1);
|
|
114
|
-
v.push(2);
|
|
115
|
-
v.extend([3, 4, 5]);
|
|
116
|
-
v.pop();
|
|
117
|
-
|
|
118
|
-
// Iteration
|
|
119
|
-
for item in &v {
|
|
120
|
-
println!("{}", item);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
// Slicing
|
|
124
|
-
let slice: &[i32] = &v[..];
|
|
125
|
-
|
|
126
|
-
// Conversion
|
|
127
|
-
let vec: Vec<i32> = v.into();
|
|
128
|
-
let thin: ThinVec<i32> = vec.into();
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
## Cargo.toml
|
|
132
|
-
|
|
133
|
-
```toml
|
|
134
|
-
[dependencies]
|
|
135
|
-
thin-vec = "0.2"
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
## See Also
|
|
139
|
-
|
|
140
|
-
- [mem-smallvec](./mem-smallvec.md) - Stack-allocated small vecs
|
|
141
|
-
- [mem-boxed-slice](./mem-boxed-slice.md) - Fixed-size heap slices
|
|
142
|
-
- [mem-with-capacity](./mem-with-capacity.md) - Pre-allocation strategies
|
|
@@ -1,156 +0,0 @@
|
|
|
1
|
-
# mem-with-capacity
|
|
2
|
-
|
|
3
|
-
> Use `with_capacity()` when size is known
|
|
4
|
-
|
|
5
|
-
## Why It Matters
|
|
6
|
-
|
|
7
|
-
When you know (or can estimate) the final size of a collection, pre-allocating avoids multiple reallocations as it grows. Each reallocation copies all existing elements, so avoiding them can dramatically improve performance.
|
|
8
|
-
|
|
9
|
-
## Bad
|
|
10
|
-
|
|
11
|
-
```rust
|
|
12
|
-
// Vec starts at capacity 0, reallocates at 4, 8, 16, 32...
|
|
13
|
-
let mut results = Vec::new();
|
|
14
|
-
for i in 0..1000 {
|
|
15
|
-
results.push(process(i)); // ~10 reallocations!
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
// String grows similarly
|
|
19
|
-
let mut output = String::new();
|
|
20
|
-
for word in words {
|
|
21
|
-
output.push_str(word);
|
|
22
|
-
output.push(' ');
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
// HashMap default capacity is small
|
|
26
|
-
let mut map = HashMap::new();
|
|
27
|
-
for (k, v) in pairs { // Many reallocations
|
|
28
|
-
map.insert(k, v);
|
|
29
|
-
}
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
## Good
|
|
33
|
-
|
|
34
|
-
```rust
|
|
35
|
-
// Pre-allocate exact size
|
|
36
|
-
let mut results = Vec::with_capacity(1000);
|
|
37
|
-
for i in 0..1000 {
|
|
38
|
-
results.push(process(i)); // Zero reallocations!
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// Or use collect with size hint (iterator provides capacity)
|
|
42
|
-
let results: Vec<_> = (0..1000).map(process).collect();
|
|
43
|
-
|
|
44
|
-
// Pre-allocate string
|
|
45
|
-
let estimated_len = words.iter().map(|w| w.len() + 1).sum();
|
|
46
|
-
let mut output = String::with_capacity(estimated_len);
|
|
47
|
-
for word in words {
|
|
48
|
-
output.push_str(word);
|
|
49
|
-
output.push(' ');
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// Pre-allocate HashMap
|
|
53
|
-
let mut map = HashMap::with_capacity(pairs.len());
|
|
54
|
-
for (k, v) in pairs {
|
|
55
|
-
map.insert(k, v);
|
|
56
|
-
}
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
## Collection Capacity Methods
|
|
60
|
-
|
|
61
|
-
```rust
|
|
62
|
-
// Vec
|
|
63
|
-
let mut v = Vec::with_capacity(100);
|
|
64
|
-
v.reserve(50); // Ensure at least 50 more slots
|
|
65
|
-
v.reserve_exact(50); // Ensure exactly 50 more (no extra)
|
|
66
|
-
v.shrink_to_fit(); // Release unused capacity
|
|
67
|
-
|
|
68
|
-
// String
|
|
69
|
-
let mut s = String::with_capacity(100);
|
|
70
|
-
s.reserve(50);
|
|
71
|
-
|
|
72
|
-
// HashMap / HashSet
|
|
73
|
-
let mut m = HashMap::with_capacity(100);
|
|
74
|
-
m.reserve(50);
|
|
75
|
-
|
|
76
|
-
// VecDeque
|
|
77
|
-
let mut d = VecDeque::with_capacity(100);
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
## Estimating Capacity
|
|
81
|
-
|
|
82
|
-
```rust
|
|
83
|
-
// From iterator length
|
|
84
|
-
fn collect_results(items: &[Item]) -> Vec<Output> {
|
|
85
|
-
let mut results = Vec::with_capacity(items.len());
|
|
86
|
-
for item in items {
|
|
87
|
-
results.push(process(item));
|
|
88
|
-
}
|
|
89
|
-
results
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// From filter estimate (if ~10% pass filter)
|
|
93
|
-
fn filter_valid(items: &[Item]) -> Vec<&Item> {
|
|
94
|
-
let mut valid = Vec::with_capacity(items.len() / 10);
|
|
95
|
-
for item in items {
|
|
96
|
-
if item.is_valid() {
|
|
97
|
-
valid.push(item);
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
valid
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// String from parts
|
|
104
|
-
fn join_with_sep(parts: &[&str], sep: &str) -> String {
|
|
105
|
-
let total_len: usize = parts.iter().map(|p| p.len()).sum();
|
|
106
|
-
let sep_len = if parts.is_empty() { 0 } else { sep.len() * (parts.len() - 1) };
|
|
107
|
-
|
|
108
|
-
let mut result = String::with_capacity(total_len + sep_len);
|
|
109
|
-
for (i, part) in parts.iter().enumerate() {
|
|
110
|
-
if i > 0 {
|
|
111
|
-
result.push_str(sep);
|
|
112
|
-
}
|
|
113
|
-
result.push_str(part);
|
|
114
|
-
}
|
|
115
|
-
result
|
|
116
|
-
}
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
## Evidence from Production Code
|
|
120
|
-
|
|
121
|
-
From fd (file finder):
|
|
122
|
-
```rust
|
|
123
|
-
// https://github.com/sharkdp/fd/blob/master/src/walk.rs
|
|
124
|
-
struct ReceiverBuffer<'a, W> {
|
|
125
|
-
buffer: Vec<DirEntry>,
|
|
126
|
-
// ...
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
impl<'a, W: Write> ReceiverBuffer<'a, W> {
|
|
130
|
-
fn new(...) -> Self {
|
|
131
|
-
Self {
|
|
132
|
-
buffer: Vec::with_capacity(MAX_BUFFER_LENGTH),
|
|
133
|
-
// ...
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
## When to Skip
|
|
140
|
-
|
|
141
|
-
```rust
|
|
142
|
-
// Unknown size, small expected
|
|
143
|
-
let mut small: Vec<i32> = Vec::new(); // OK for small collections
|
|
144
|
-
|
|
145
|
-
// Using collect() with good size_hint
|
|
146
|
-
let v: Vec<_> = iter.collect(); // collect() uses size_hint
|
|
147
|
-
|
|
148
|
-
// Capacity overhead exceeds benefit
|
|
149
|
-
let mut rarely_used = Vec::new(); // OK if rarely grown
|
|
150
|
-
```
|
|
151
|
-
|
|
152
|
-
## See Also
|
|
153
|
-
|
|
154
|
-
- [mem-reuse-collections](mem-reuse-collections.md) - Reuse collections with clear()
|
|
155
|
-
- [mem-smallvec](mem-smallvec.md) - Use SmallVec for usually-small collections
|
|
156
|
-
- [perf-extend-batch](perf-extend-batch.md) - Use extend() for batch insertions
|
|
@@ -1,172 +0,0 @@
|
|
|
1
|
-
# mem-write-over-format
|
|
2
|
-
|
|
3
|
-
> Use `write!()` into existing buffers instead of `format!()` allocations
|
|
4
|
-
|
|
5
|
-
## Why It Matters
|
|
6
|
-
|
|
7
|
-
`format!()` always allocates a new `String`. In hot paths or loops, these allocations add up. `write!()` writes directly into an existing buffer, reusing its capacity. For high-frequency formatting operations, this can eliminate significant allocator overhead.
|
|
8
|
-
|
|
9
|
-
## Bad
|
|
10
|
-
|
|
11
|
-
```rust
|
|
12
|
-
fn log_event(event: &Event, output: &mut Vec<u8>) {
|
|
13
|
-
// format! allocates a new String every call
|
|
14
|
-
let line = format!(
|
|
15
|
-
"[{}] {}: {}\n",
|
|
16
|
-
event.timestamp,
|
|
17
|
-
event.level,
|
|
18
|
-
event.message
|
|
19
|
-
);
|
|
20
|
-
output.extend_from_slice(line.as_bytes());
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
fn build_response(items: &[Item]) -> String {
|
|
24
|
-
let mut result = String::new();
|
|
25
|
-
|
|
26
|
-
for item in items {
|
|
27
|
-
// format! allocates for each item
|
|
28
|
-
result.push_str(&format!("{}: {}\n", item.name, item.value));
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
result
|
|
32
|
-
}
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
## Good
|
|
36
|
-
|
|
37
|
-
```rust
|
|
38
|
-
use std::fmt::Write;
|
|
39
|
-
|
|
40
|
-
fn log_event(event: &Event, output: &mut Vec<u8>) {
|
|
41
|
-
use std::io::Write;
|
|
42
|
-
// write! to Vec<u8> directly, no intermediate allocation
|
|
43
|
-
write!(
|
|
44
|
-
output,
|
|
45
|
-
"[{}] {}: {}\n",
|
|
46
|
-
event.timestamp,
|
|
47
|
-
event.level,
|
|
48
|
-
event.message
|
|
49
|
-
).unwrap();
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
fn build_response(items: &[Item]) -> String {
|
|
53
|
-
use std::fmt::Write;
|
|
54
|
-
|
|
55
|
-
let mut result = String::with_capacity(items.len() * 64);
|
|
56
|
-
|
|
57
|
-
for item in items {
|
|
58
|
-
// write! into existing String, reuses capacity
|
|
59
|
-
write!(&mut result, "{}: {}\n", item.name, item.value).unwrap();
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
result
|
|
63
|
-
}
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
## Write Trait Varieties
|
|
67
|
-
|
|
68
|
-
```rust
|
|
69
|
-
// std::fmt::Write - for String, &mut String
|
|
70
|
-
use std::fmt::Write as FmtWrite;
|
|
71
|
-
let mut s = String::new();
|
|
72
|
-
write!(&mut s, "Hello {}", 42).unwrap();
|
|
73
|
-
|
|
74
|
-
// std::io::Write - for Vec<u8>, File, TcpStream, etc.
|
|
75
|
-
use std::io::Write as IoWrite;
|
|
76
|
-
let mut v: Vec<u8> = Vec::new();
|
|
77
|
-
write!(&mut v, "Hello {}", 42).unwrap();
|
|
78
|
-
|
|
79
|
-
// Both can fail in principle, but String/Vec never fail
|
|
80
|
-
// Still need .unwrap() due to Result return type
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
## Reusable Formatting Buffer
|
|
84
|
-
|
|
85
|
-
```rust
|
|
86
|
-
use std::fmt::Write;
|
|
87
|
-
|
|
88
|
-
struct Formatter {
|
|
89
|
-
buffer: String,
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
impl Formatter {
|
|
93
|
-
fn new() -> Self {
|
|
94
|
-
Self { buffer: String::with_capacity(1024) }
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
fn format_event(&mut self, event: &Event) -> &str {
|
|
98
|
-
self.buffer.clear(); // Reuse allocation
|
|
99
|
-
write!(
|
|
100
|
-
&mut self.buffer,
|
|
101
|
-
"[{}] {}",
|
|
102
|
-
event.timestamp,
|
|
103
|
-
event.message
|
|
104
|
-
).unwrap();
|
|
105
|
-
&self.buffer
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// Usage
|
|
110
|
-
let mut formatter = Formatter::new();
|
|
111
|
-
for event in events {
|
|
112
|
-
let formatted = formatter.format_event(event);
|
|
113
|
-
send_log(formatted);
|
|
114
|
-
}
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
## writeln! for Lines
|
|
118
|
-
|
|
119
|
-
```rust
|
|
120
|
-
use std::fmt::Write;
|
|
121
|
-
|
|
122
|
-
let mut output = String::new();
|
|
123
|
-
|
|
124
|
-
// writeln! adds newline automatically
|
|
125
|
-
writeln!(&mut output, "Line 1: {}", value1).unwrap();
|
|
126
|
-
writeln!(&mut output, "Line 2: {}", value2).unwrap();
|
|
127
|
-
|
|
128
|
-
// Equivalent to
|
|
129
|
-
write!(&mut output, "Line 1: {}\n", value1).unwrap();
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
## When format! Is Fine
|
|
133
|
-
|
|
134
|
-
```rust
|
|
135
|
-
// One-time formatting, not in loop
|
|
136
|
-
let message = format!("Starting server on port {}", port);
|
|
137
|
-
log::info!("{}", message);
|
|
138
|
-
|
|
139
|
-
// Return value (can't return reference to local buffer)
|
|
140
|
-
fn describe(item: &Item) -> String {
|
|
141
|
-
format!("{}: {}", item.name, item.value) // Must allocate
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
// Debug/error paths (not hot)
|
|
145
|
-
if condition {
|
|
146
|
-
panic!("Unexpected: {}", format!("details: {:?}", debug_info));
|
|
147
|
-
}
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
## Benchmark Difference
|
|
151
|
-
|
|
152
|
-
```rust
|
|
153
|
-
// format! in loop: ~500ns per iteration (allocation heavy)
|
|
154
|
-
for i in 0..1000 {
|
|
155
|
-
let s = format!("item-{}", i);
|
|
156
|
-
process(&s);
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
// write! with reuse: ~50ns per iteration (no allocation)
|
|
160
|
-
let mut buf = String::with_capacity(32);
|
|
161
|
-
for i in 0..1000 {
|
|
162
|
-
buf.clear();
|
|
163
|
-
write!(&mut buf, "item-{}", i).unwrap();
|
|
164
|
-
process(&buf);
|
|
165
|
-
}
|
|
166
|
-
```
|
|
167
|
-
|
|
168
|
-
## See Also
|
|
169
|
-
|
|
170
|
-
- [mem-avoid-format](./mem-avoid-format.md) - General format! avoidance patterns
|
|
171
|
-
- [mem-reuse-collections](./mem-reuse-collections.md) - Reusing buffers in loops
|
|
172
|
-
- [mem-with-capacity](./mem-with-capacity.md) - Pre-allocating string capacity
|
|
@@ -1,164 +0,0 @@
|
|
|
1
|
-
# mem-zero-copy
|
|
2
|
-
|
|
3
|
-
> Use zero-copy patterns with slices and `Bytes`
|
|
4
|
-
|
|
5
|
-
## Why It Matters
|
|
6
|
-
|
|
7
|
-
Zero-copy means working with data without copying it. Instead of allocating new memory and copying bytes, you work with references to the original data. This dramatically reduces memory usage and improves performance, especially for large data.
|
|
8
|
-
|
|
9
|
-
## Bad
|
|
10
|
-
|
|
11
|
-
```rust
|
|
12
|
-
// Copies every line into a new String
|
|
13
|
-
fn get_lines(data: &str) -> Vec<String> {
|
|
14
|
-
data.lines()
|
|
15
|
-
.map(|line| line.to_string()) // Allocates!
|
|
16
|
-
.collect()
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
// Copies the entire buffer
|
|
20
|
-
fn process_packet(buffer: &[u8]) -> Vec<u8> {
|
|
21
|
-
let header = buffer[0..16].to_vec(); // Copy!
|
|
22
|
-
let body = buffer[16..].to_vec(); // Copy!
|
|
23
|
-
// Process...
|
|
24
|
-
[header, body].concat() // Another copy!
|
|
25
|
-
}
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
## Good
|
|
29
|
-
|
|
30
|
-
```rust
|
|
31
|
-
// Zero-copy: returns references to original data
|
|
32
|
-
fn get_lines(data: &str) -> Vec<&str> {
|
|
33
|
-
data.lines().collect() // Just pointers!
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// Zero-copy with slices
|
|
37
|
-
fn process_packet(buffer: &[u8]) -> (&[u8], &[u8]) {
|
|
38
|
-
let header = &buffer[0..16]; // Just a pointer + length
|
|
39
|
-
let body = &buffer[16..]; // Just a pointer + length
|
|
40
|
-
(header, body)
|
|
41
|
-
}
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
## Using bytes::Bytes
|
|
45
|
-
|
|
46
|
-
```rust
|
|
47
|
-
use bytes::Bytes;
|
|
48
|
-
|
|
49
|
-
// Bytes provides zero-copy slicing with reference counting
|
|
50
|
-
let data = Bytes::from("hello world");
|
|
51
|
-
|
|
52
|
-
// Slicing doesn't copy - just increments refcount
|
|
53
|
-
let hello = data.slice(0..5); // Zero-copy!
|
|
54
|
-
let world = data.slice(6..11); // Zero-copy!
|
|
55
|
-
|
|
56
|
-
// Both hello and world share the underlying allocation
|
|
57
|
-
// Memory is freed when all references are dropped
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
## Real-World Pattern from Deno
|
|
61
|
-
|
|
62
|
-
```rust
|
|
63
|
-
// https://github.com/denoland/deno/blob/main/ext/http/lib.rs
|
|
64
|
-
fn method_to_cow(method: &http::Method) -> Cow<'static, str> {
|
|
65
|
-
match *method {
|
|
66
|
-
Method::GET => Cow::Borrowed("GET"), // Zero-copy
|
|
67
|
-
Method::POST => Cow::Borrowed("POST"), // Zero-copy
|
|
68
|
-
Method::PUT => Cow::Borrowed("PUT"), // Zero-copy
|
|
69
|
-
_ => Cow::Owned(method.to_string()), // Only copies for rare methods
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
## Zero-Copy Parsing
|
|
75
|
-
|
|
76
|
-
```rust
|
|
77
|
-
// Bad: Copies each parsed field
|
|
78
|
-
struct ParsedBad {
|
|
79
|
-
name: String,
|
|
80
|
-
value: String,
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
fn parse_bad(input: &str) -> ParsedBad {
|
|
84
|
-
let (name, value) = input.split_once('=').unwrap();
|
|
85
|
-
ParsedBad {
|
|
86
|
-
name: name.to_string(), // Copy!
|
|
87
|
-
value: value.to_string(), // Copy!
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
// Good: References into original string
|
|
92
|
-
struct Parsed<'a> {
|
|
93
|
-
name: &'a str,
|
|
94
|
-
value: &'a str,
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
fn parse_good(input: &str) -> Parsed<'_> {
|
|
98
|
-
let (name, value) = input.split_once('=').unwrap();
|
|
99
|
-
Parsed { name, value } // Zero-copy!
|
|
100
|
-
}
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
## Combining with Cow
|
|
104
|
-
|
|
105
|
-
```rust
|
|
106
|
-
use std::borrow::Cow;
|
|
107
|
-
|
|
108
|
-
// Zero-copy when possible, copy when needed
|
|
109
|
-
fn normalize<'a>(input: &'a str) -> Cow<'a, str> {
|
|
110
|
-
if input.contains('\t') {
|
|
111
|
-
// Must copy to modify
|
|
112
|
-
Cow::Owned(input.replace('\t', " "))
|
|
113
|
-
} else {
|
|
114
|
-
// Zero-copy reference
|
|
115
|
-
Cow::Borrowed(input)
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
## memchr for Fast Searching
|
|
121
|
-
|
|
122
|
-
```rust
|
|
123
|
-
use memchr::memchr;
|
|
124
|
-
|
|
125
|
-
// Fast byte search using SIMD
|
|
126
|
-
fn find_newline(data: &[u8]) -> Option<usize> {
|
|
127
|
-
memchr(b'\n', data) // SIMD-accelerated, no allocation
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
// Find all occurrences
|
|
131
|
-
use memchr::memchr_iter;
|
|
132
|
-
|
|
133
|
-
fn count_newlines(data: &[u8]) -> usize {
|
|
134
|
-
memchr_iter(b'\n', data).count()
|
|
135
|
-
}
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
## When Zero-Copy Isn't Possible
|
|
139
|
-
|
|
140
|
-
```rust
|
|
141
|
-
// Need to modify data - must copy
|
|
142
|
-
fn uppercase(s: &str) -> String {
|
|
143
|
-
s.to_uppercase() // Creates new String
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// Need data to outlive source
|
|
147
|
-
fn store_for_later(s: &str) -> String {
|
|
148
|
-
s.to_string() // Must copy for ownership
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
// Cross-thread transfer (without Arc)
|
|
152
|
-
fn send_to_thread(data: &[u8]) {
|
|
153
|
-
let owned = data.to_vec(); // Must copy
|
|
154
|
-
std::thread::spawn(move || {
|
|
155
|
-
process(&owned);
|
|
156
|
-
});
|
|
157
|
-
}
|
|
158
|
-
```
|
|
159
|
-
|
|
160
|
-
## See Also
|
|
161
|
-
|
|
162
|
-
- [own-cow-conditional](own-cow-conditional.md) - Use Cow for conditional ownership
|
|
163
|
-
- [own-borrow-over-clone](own-borrow-over-clone.md) - Prefer borrowing over cloning
|
|
164
|
-
- [mem-arena-allocator](mem-arena-allocator.md) - Arena allocators for batch operations
|