agy-superpowers 5.1.4 → 5.1.6
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/package.json +1 -1
- package/template/agent/rules/debug-confirmation-policy.md +34 -0
- package/template/agent/rules/language-matching.md +32 -0
- package/template/agent/skills/rust-developer/SKILL.md +281 -0
- package/template/agent/skills/rust-developer/references/rust-rules/_sections.md +231 -0
- package/template/agent/skills/rust-developer/references/rust-rules/anti-clone-excessive.md +124 -0
- package/template/agent/skills/rust-developer/references/rust-rules/anti-collect-intermediate.md +131 -0
- package/template/agent/skills/rust-developer/references/rust-rules/anti-empty-catch.md +132 -0
- package/template/agent/skills/rust-developer/references/rust-rules/anti-expect-lazy.md +95 -0
- package/template/agent/skills/rust-developer/references/rust-rules/anti-format-hot-path.md +141 -0
- package/template/agent/skills/rust-developer/references/rust-rules/anti-index-over-iter.md +125 -0
- package/template/agent/skills/rust-developer/references/rust-rules/anti-lock-across-await.md +127 -0
- package/template/agent/skills/rust-developer/references/rust-rules/anti-over-abstraction.md +120 -0
- package/template/agent/skills/rust-developer/references/rust-rules/anti-panic-expected.md +131 -0
- package/template/agent/skills/rust-developer/references/rust-rules/anti-premature-optimize.md +156 -0
- package/template/agent/skills/rust-developer/references/rust-rules/anti-string-for-str.md +122 -0
- package/template/agent/skills/rust-developer/references/rust-rules/anti-stringly-typed.md +167 -0
- package/template/agent/skills/rust-developer/references/rust-rules/anti-type-erasure.md +134 -0
- package/template/agent/skills/rust-developer/references/rust-rules/anti-unwrap-abuse.md +143 -0
- package/template/agent/skills/rust-developer/references/rust-rules/anti-vec-for-slice.md +121 -0
- package/template/agent/skills/rust-developer/references/rust-rules/api-builder-must-use.md +143 -0
- package/template/agent/skills/rust-developer/references/rust-rules/api-builder-pattern.md +187 -0
- package/template/agent/skills/rust-developer/references/rust-rules/api-common-traits.md +165 -0
- package/template/agent/skills/rust-developer/references/rust-rules/api-default-impl.md +177 -0
- package/template/agent/skills/rust-developer/references/rust-rules/api-extension-trait.md +163 -0
- package/template/agent/skills/rust-developer/references/rust-rules/api-from-not-into.md +146 -0
- package/template/agent/skills/rust-developer/references/rust-rules/api-impl-asref.md +142 -0
- package/template/agent/skills/rust-developer/references/rust-rules/api-impl-into.md +160 -0
- package/template/agent/skills/rust-developer/references/rust-rules/api-must-use.md +125 -0
- package/template/agent/skills/rust-developer/references/rust-rules/api-newtype-safety.md +162 -0
- package/template/agent/skills/rust-developer/references/rust-rules/api-non-exhaustive.md +177 -0
- package/template/agent/skills/rust-developer/references/rust-rules/api-parse-dont-validate.md +184 -0
- package/template/agent/skills/rust-developer/references/rust-rules/api-sealed-trait.md +168 -0
- package/template/agent/skills/rust-developer/references/rust-rules/api-serde-optional.md +182 -0
- package/template/agent/skills/rust-developer/references/rust-rules/api-typestate.md +199 -0
- package/template/agent/skills/rust-developer/references/rust-rules/async-bounded-channel.md +175 -0
- package/template/agent/skills/rust-developer/references/rust-rules/async-broadcast-pubsub.md +185 -0
- package/template/agent/skills/rust-developer/references/rust-rules/async-cancellation-token.md +203 -0
- package/template/agent/skills/rust-developer/references/rust-rules/async-clone-before-await.md +171 -0
- package/template/agent/skills/rust-developer/references/rust-rules/async-join-parallel.md +158 -0
- package/template/agent/skills/rust-developer/references/rust-rules/async-joinset-structured.md +195 -0
- package/template/agent/skills/rust-developer/references/rust-rules/async-mpsc-queue.md +171 -0
- package/template/agent/skills/rust-developer/references/rust-rules/async-no-lock-await.md +156 -0
- package/template/agent/skills/rust-developer/references/rust-rules/async-oneshot-response.md +191 -0
- package/template/agent/skills/rust-developer/references/rust-rules/async-select-racing.md +198 -0
- package/template/agent/skills/rust-developer/references/rust-rules/async-spawn-blocking.md +154 -0
- package/template/agent/skills/rust-developer/references/rust-rules/async-tokio-fs.md +167 -0
- package/template/agent/skills/rust-developer/references/rust-rules/async-tokio-runtime.md +169 -0
- package/template/agent/skills/rust-developer/references/rust-rules/async-try-join.md +172 -0
- package/template/agent/skills/rust-developer/references/rust-rules/async-watch-latest.md +189 -0
- package/template/agent/skills/rust-developer/references/rust-rules/doc-all-public.md +113 -0
- package/template/agent/skills/rust-developer/references/rust-rules/doc-cargo-metadata.md +147 -0
- package/template/agent/skills/rust-developer/references/rust-rules/doc-errors-section.md +122 -0
- package/template/agent/skills/rust-developer/references/rust-rules/doc-examples-section.md +161 -0
- package/template/agent/skills/rust-developer/references/rust-rules/doc-hidden-setup.md +149 -0
- package/template/agent/skills/rust-developer/references/rust-rules/doc-intra-links.md +138 -0
- package/template/agent/skills/rust-developer/references/rust-rules/doc-link-types.md +169 -0
- package/template/agent/skills/rust-developer/references/rust-rules/doc-module-inner.md +116 -0
- package/template/agent/skills/rust-developer/references/rust-rules/doc-panics-section.md +128 -0
- package/template/agent/skills/rust-developer/references/rust-rules/doc-question-mark.md +136 -0
- package/template/agent/skills/rust-developer/references/rust-rules/doc-safety-section.md +131 -0
- package/template/agent/skills/rust-developer/references/rust-rules/err-anyhow-app.md +179 -0
- package/template/agent/skills/rust-developer/references/rust-rules/err-context-chain.md +144 -0
- package/template/agent/skills/rust-developer/references/rust-rules/err-custom-type.md +152 -0
- package/template/agent/skills/rust-developer/references/rust-rules/err-doc-errors.md +145 -0
- package/template/agent/skills/rust-developer/references/rust-rules/err-expect-bugs-only.md +133 -0
- package/template/agent/skills/rust-developer/references/rust-rules/err-from-impl.md +152 -0
- package/template/agent/skills/rust-developer/references/rust-rules/err-lowercase-msg.md +124 -0
- package/template/agent/skills/rust-developer/references/rust-rules/err-no-unwrap-prod.md +115 -0
- package/template/agent/skills/rust-developer/references/rust-rules/err-question-mark.md +151 -0
- package/template/agent/skills/rust-developer/references/rust-rules/err-result-over-panic.md +130 -0
- package/template/agent/skills/rust-developer/references/rust-rules/err-source-chain.md +155 -0
- package/template/agent/skills/rust-developer/references/rust-rules/err-thiserror-lib.md +171 -0
- package/template/agent/skills/rust-developer/references/rust-rules/lint-cargo-metadata.md +138 -0
- package/template/agent/skills/rust-developer/references/rust-rules/lint-deny-correctness.md +107 -0
- package/template/agent/skills/rust-developer/references/rust-rules/lint-missing-docs.md +154 -0
- package/template/agent/skills/rust-developer/references/rust-rules/lint-pedantic-selective.md +118 -0
- package/template/agent/skills/rust-developer/references/rust-rules/lint-rustfmt-check.md +157 -0
- package/template/agent/skills/rust-developer/references/rust-rules/lint-unsafe-doc.md +133 -0
- package/template/agent/skills/rust-developer/references/rust-rules/lint-warn-complexity.md +131 -0
- package/template/agent/skills/rust-developer/references/rust-rules/lint-warn-perf.md +136 -0
- package/template/agent/skills/rust-developer/references/rust-rules/lint-warn-style.md +135 -0
- package/template/agent/skills/rust-developer/references/rust-rules/lint-warn-suspicious.md +122 -0
- package/template/agent/skills/rust-developer/references/rust-rules/lint-workspace-lints.md +172 -0
- package/template/agent/skills/rust-developer/references/rust-rules/mem-arena-allocator.md +168 -0
- package/template/agent/skills/rust-developer/references/rust-rules/mem-arrayvec.md +142 -0
- package/template/agent/skills/rust-developer/references/rust-rules/mem-assert-type-size.md +168 -0
- package/template/agent/skills/rust-developer/references/rust-rules/mem-avoid-format.md +147 -0
- package/template/agent/skills/rust-developer/references/rust-rules/mem-box-large-variant.md +158 -0
- package/template/agent/skills/rust-developer/references/rust-rules/mem-boxed-slice.md +139 -0
- package/template/agent/skills/rust-developer/references/rust-rules/mem-clone-from.md +147 -0
- package/template/agent/skills/rust-developer/references/rust-rules/mem-compact-string.md +149 -0
- package/template/agent/skills/rust-developer/references/rust-rules/mem-reuse-collections.md +174 -0
- package/template/agent/skills/rust-developer/references/rust-rules/mem-smaller-integers.md +159 -0
- package/template/agent/skills/rust-developer/references/rust-rules/mem-smallvec.md +138 -0
- package/template/agent/skills/rust-developer/references/rust-rules/mem-thinvec.md +142 -0
- package/template/agent/skills/rust-developer/references/rust-rules/mem-with-capacity.md +156 -0
- package/template/agent/skills/rust-developer/references/rust-rules/mem-write-over-format.md +172 -0
- package/template/agent/skills/rust-developer/references/rust-rules/mem-zero-copy.md +164 -0
- package/template/agent/skills/rust-developer/references/rust-rules/name-acronym-word.md +99 -0
- package/template/agent/skills/rust-developer/references/rust-rules/name-as-free.md +104 -0
- package/template/agent/skills/rust-developer/references/rust-rules/name-consts-screaming.md +94 -0
- package/template/agent/skills/rust-developer/references/rust-rules/name-crate-no-rs.md +78 -0
- package/template/agent/skills/rust-developer/references/rust-rules/name-funcs-snake.md +76 -0
- package/template/agent/skills/rust-developer/references/rust-rules/name-into-ownership.md +123 -0
- package/template/agent/skills/rust-developer/references/rust-rules/name-is-has-bool.md +127 -0
- package/template/agent/skills/rust-developer/references/rust-rules/name-iter-convention.md +129 -0
- package/template/agent/skills/rust-developer/references/rust-rules/name-iter-method.md +131 -0
- package/template/agent/skills/rust-developer/references/rust-rules/name-iter-type-match.md +142 -0
- package/template/agent/skills/rust-developer/references/rust-rules/name-lifetime-short.md +86 -0
- package/template/agent/skills/rust-developer/references/rust-rules/name-no-get-prefix.md +154 -0
- package/template/agent/skills/rust-developer/references/rust-rules/name-to-expensive.md +118 -0
- package/template/agent/skills/rust-developer/references/rust-rules/name-type-param-single.md +92 -0
- package/template/agent/skills/rust-developer/references/rust-rules/name-types-camel.md +65 -0
- package/template/agent/skills/rust-developer/references/rust-rules/name-variants-camel.md +101 -0
- package/template/agent/skills/rust-developer/references/rust-rules/opt-bounds-check.md +161 -0
- package/template/agent/skills/rust-developer/references/rust-rules/opt-cache-friendly.md +187 -0
- package/template/agent/skills/rust-developer/references/rust-rules/opt-codegen-units.md +142 -0
- package/template/agent/skills/rust-developer/references/rust-rules/opt-cold-unlikely.md +152 -0
- package/template/agent/skills/rust-developer/references/rust-rules/opt-inline-always-rare.md +141 -0
- package/template/agent/skills/rust-developer/references/rust-rules/opt-inline-never-cold.md +181 -0
- package/template/agent/skills/rust-developer/references/rust-rules/opt-inline-small.md +160 -0
- package/template/agent/skills/rust-developer/references/rust-rules/opt-likely-hint.md +171 -0
- package/template/agent/skills/rust-developer/references/rust-rules/opt-lto-release.md +130 -0
- package/template/agent/skills/rust-developer/references/rust-rules/opt-pgo-profile.md +167 -0
- package/template/agent/skills/rust-developer/references/rust-rules/opt-simd-portable.md +144 -0
- package/template/agent/skills/rust-developer/references/rust-rules/opt-target-cpu.md +154 -0
- package/template/agent/skills/rust-developer/references/rust-rules/own-arc-shared.md +141 -0
- package/template/agent/skills/rust-developer/references/rust-rules/own-borrow-over-clone.md +95 -0
- package/template/agent/skills/rust-developer/references/rust-rules/own-clone-explicit.md +135 -0
- package/template/agent/skills/rust-developer/references/rust-rules/own-copy-small.md +124 -0
- package/template/agent/skills/rust-developer/references/rust-rules/own-cow-conditional.md +135 -0
- package/template/agent/skills/rust-developer/references/rust-rules/own-lifetime-elision.md +134 -0
- package/template/agent/skills/rust-developer/references/rust-rules/own-move-large.md +134 -0
- package/template/agent/skills/rust-developer/references/rust-rules/own-mutex-interior.md +105 -0
- package/template/agent/skills/rust-developer/references/rust-rules/own-rc-single-thread.md +65 -0
- package/template/agent/skills/rust-developer/references/rust-rules/own-refcell-interior.md +97 -0
- package/template/agent/skills/rust-developer/references/rust-rules/own-rwlock-readers.md +122 -0
- package/template/agent/skills/rust-developer/references/rust-rules/own-slice-over-vec.md +119 -0
- package/template/agent/skills/rust-developer/references/rust-rules/perf-black-box-bench.md +153 -0
- package/template/agent/skills/rust-developer/references/rust-rules/perf-chain-avoid.md +136 -0
- package/template/agent/skills/rust-developer/references/rust-rules/perf-collect-into.md +133 -0
- package/template/agent/skills/rust-developer/references/rust-rules/perf-collect-once.md +120 -0
- package/template/agent/skills/rust-developer/references/rust-rules/perf-drain-reuse.md +137 -0
- package/template/agent/skills/rust-developer/references/rust-rules/perf-entry-api.md +134 -0
- package/template/agent/skills/rust-developer/references/rust-rules/perf-extend-batch.md +150 -0
- package/template/agent/skills/rust-developer/references/rust-rules/perf-iter-lazy.md +123 -0
- package/template/agent/skills/rust-developer/references/rust-rules/perf-iter-over-index.md +113 -0
- package/template/agent/skills/rust-developer/references/rust-rules/perf-profile-first.md +175 -0
- package/template/agent/skills/rust-developer/references/rust-rules/perf-release-profile.md +149 -0
- package/template/agent/skills/rust-developer/references/rust-rules/proj-bin-dir.md +142 -0
- package/template/agent/skills/rust-developer/references/rust-rules/proj-flat-small.md +133 -0
- package/template/agent/skills/rust-developer/references/rust-rules/proj-lib-main-split.md +148 -0
- package/template/agent/skills/rust-developer/references/rust-rules/proj-mod-by-feature.md +130 -0
- package/template/agent/skills/rust-developer/references/rust-rules/proj-mod-rs-dir.md +120 -0
- package/template/agent/skills/rust-developer/references/rust-rules/proj-prelude-module.md +155 -0
- package/template/agent/skills/rust-developer/references/rust-rules/proj-pub-crate-internal.md +139 -0
- package/template/agent/skills/rust-developer/references/rust-rules/proj-pub-super-parent.md +135 -0
- package/template/agent/skills/rust-developer/references/rust-rules/proj-pub-use-reexport.md +162 -0
- package/template/agent/skills/rust-developer/references/rust-rules/proj-workspace-deps.md +186 -0
- package/template/agent/skills/rust-developer/references/rust-rules/proj-workspace-large.md +162 -0
- package/template/agent/skills/rust-developer/references/rust-rules/test-arrange-act-assert.md +160 -0
- package/template/agent/skills/rust-developer/references/rust-rules/test-cfg-test-module.md +151 -0
- package/template/agent/skills/rust-developer/references/rust-rules/test-criterion-bench.md +171 -0
- package/template/agent/skills/rust-developer/references/rust-rules/test-descriptive-names.md +142 -0
- package/template/agent/skills/rust-developer/references/rust-rules/test-doctest-examples.md +168 -0
- package/template/agent/skills/rust-developer/references/rust-rules/test-fixture-raii.md +151 -0
- package/template/agent/skills/rust-developer/references/rust-rules/test-integration-dir.md +144 -0
- package/template/agent/skills/rust-developer/references/rust-rules/test-mock-traits.md +189 -0
- package/template/agent/skills/rust-developer/references/rust-rules/test-mockall-mocking.md +226 -0
- package/template/agent/skills/rust-developer/references/rust-rules/test-proptest-properties.md +161 -0
- package/template/agent/skills/rust-developer/references/rust-rules/test-should-panic.md +130 -0
- package/template/agent/skills/rust-developer/references/rust-rules/test-tokio-async.md +154 -0
- package/template/agent/skills/rust-developer/references/rust-rules/test-use-super.md +127 -0
- package/template/agent/skills/rust-developer/references/rust-rules/type-enum-states.md +154 -0
- package/template/agent/skills/rust-developer/references/rust-rules/type-generic-bounds.md +142 -0
- package/template/agent/skills/rust-developer/references/rust-rules/type-never-diverge.md +146 -0
- package/template/agent/skills/rust-developer/references/rust-rules/type-newtype-ids.md +160 -0
- package/template/agent/skills/rust-developer/references/rust-rules/type-newtype-validated.md +159 -0
- package/template/agent/skills/rust-developer/references/rust-rules/type-no-stringly.md +144 -0
- package/template/agent/skills/rust-developer/references/rust-rules/type-option-nullable.md +137 -0
- package/template/agent/skills/rust-developer/references/rust-rules/type-phantom-marker.md +188 -0
- package/template/agent/skills/rust-developer/references/rust-rules/type-repr-transparent.md +143 -0
- package/template/agent/skills/rust-developer/references/rust-rules/type-result-fallible.md +131 -0
- package/template/agent/skills/systematic-debugging/SKILL.md +17 -0
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# anti-string-for-str
|
|
2
|
+
|
|
3
|
+
> Don't accept &String when &str works
|
|
4
|
+
|
|
5
|
+
## Why It Matters
|
|
6
|
+
|
|
7
|
+
`&String` is strictly less flexible than `&str`. A `&str` can be created from `String`, `&str`, literals, and slices. A `&String` requires exactly a `String`. This forces callers to allocate when they might not need to.
|
|
8
|
+
|
|
9
|
+
## Bad
|
|
10
|
+
|
|
11
|
+
```rust
|
|
12
|
+
// Forces callers to have a String
|
|
13
|
+
fn greet(name: &String) {
|
|
14
|
+
println!("Hello, {}", name);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Caller must allocate
|
|
18
|
+
greet(&"Alice".to_string()); // Unnecessary allocation
|
|
19
|
+
greet(&name); // Only works if name is String
|
|
20
|
+
|
|
21
|
+
// In struct
|
|
22
|
+
struct Config {
|
|
23
|
+
name: String,
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
impl Config {
|
|
27
|
+
fn set_name(&mut self, name: &String) { // Too restrictive
|
|
28
|
+
self.name = name.clone();
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Good
|
|
34
|
+
|
|
35
|
+
```rust
|
|
36
|
+
// Accept &str - works with String, &str, literals
|
|
37
|
+
fn greet(name: &str) {
|
|
38
|
+
println!("Hello, {}", name);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// All these work
|
|
42
|
+
greet("Alice"); // String literal
|
|
43
|
+
greet(&name); // &String coerces to &str
|
|
44
|
+
greet(name.as_str()); // Explicit &str
|
|
45
|
+
|
|
46
|
+
// In struct
|
|
47
|
+
impl Config {
|
|
48
|
+
fn set_name(&mut self, name: &str) {
|
|
49
|
+
self.name = name.to_string();
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Or accept owned String if caller usually has one
|
|
53
|
+
fn set_name_owned(&mut self, name: String) {
|
|
54
|
+
self.name = name;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Or be generic
|
|
58
|
+
fn set_name_into(&mut self, name: impl Into<String>) {
|
|
59
|
+
self.name = name.into();
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Deref Coercion
|
|
65
|
+
|
|
66
|
+
`String` implements `Deref<Target = str>`, so `&String` automatically coerces to `&str`:
|
|
67
|
+
|
|
68
|
+
```rust
|
|
69
|
+
fn takes_str(s: &str) { }
|
|
70
|
+
|
|
71
|
+
let owned = String::from("hello");
|
|
72
|
+
takes_str(&owned); // &String -> &str via Deref
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## When to Accept &String
|
|
76
|
+
|
|
77
|
+
Rarely. Maybe if you need `String`-specific methods:
|
|
78
|
+
|
|
79
|
+
```rust
|
|
80
|
+
fn needs_capacity(s: &String) -> usize {
|
|
81
|
+
s.capacity() // Only String has capacity()
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
But usually you'd take `&str` and let the caller manage the `String`.
|
|
86
|
+
|
|
87
|
+
## Pattern: Flexible APIs
|
|
88
|
+
|
|
89
|
+
```rust
|
|
90
|
+
// Most flexible: accept anything that can become &str
|
|
91
|
+
fn process(input: impl AsRef<str>) {
|
|
92
|
+
let s: &str = input.as_ref();
|
|
93
|
+
// ...
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
process("literal");
|
|
97
|
+
process(String::from("owned"));
|
|
98
|
+
process(&some_string);
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Similar Anti-patterns
|
|
102
|
+
|
|
103
|
+
| Anti-pattern | Better |
|
|
104
|
+
|--------------|--------|
|
|
105
|
+
| `&String` | `&str` |
|
|
106
|
+
| `&Vec<T>` | `&[T]` |
|
|
107
|
+
| `&Box<T>` | `&T` |
|
|
108
|
+
| `&PathBuf` | `&Path` |
|
|
109
|
+
| `&OsString` | `&OsStr` |
|
|
110
|
+
|
|
111
|
+
## Clippy Detection
|
|
112
|
+
|
|
113
|
+
```toml
|
|
114
|
+
[lints.clippy]
|
|
115
|
+
ptr_arg = "warn" # Catches &String, &Vec, &PathBuf
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## See Also
|
|
119
|
+
|
|
120
|
+
- [anti-vec-for-slice](./anti-vec-for-slice.md) - Similar pattern for Vec
|
|
121
|
+
- [own-slice-over-vec](./own-slice-over-vec.md) - Slice patterns
|
|
122
|
+
- [api-impl-asref](./api-impl-asref.md) - AsRef pattern
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# anti-stringly-typed
|
|
2
|
+
|
|
3
|
+
> Don't use strings where enums or newtypes would provide type safety
|
|
4
|
+
|
|
5
|
+
## Why It Matters
|
|
6
|
+
|
|
7
|
+
Strings are the most primitive way to represent data—they accept any value, provide no validation, and offer no IDE support. When you have a fixed set of valid values or a semantic type, use enums or newtypes. The compiler catches mistakes at compile time instead of runtime.
|
|
8
|
+
|
|
9
|
+
## Bad
|
|
10
|
+
|
|
11
|
+
```rust
|
|
12
|
+
fn process_order(status: &str, priority: &str) {
|
|
13
|
+
// What are valid statuses? "pending"? "Pending"? "PENDING"?
|
|
14
|
+
// What are valid priorities? "high"? "1"? "urgent"?
|
|
15
|
+
match status {
|
|
16
|
+
"pending" => { ... }
|
|
17
|
+
"completed" => { ... }
|
|
18
|
+
_ => panic!("unknown status"), // Runtime error
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
struct User {
|
|
23
|
+
email: String, // Any string, even "not an email"
|
|
24
|
+
phone: String, // Any string, even "hello"
|
|
25
|
+
user_id: String, // Could be confused with other string IDs
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Easy to make mistakes
|
|
29
|
+
process_order("complete", "high"); // Typo: "complete" vs "completed"
|
|
30
|
+
process_order("high", "pending"); // Swapped arguments - compiles!
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Good
|
|
34
|
+
|
|
35
|
+
```rust
|
|
36
|
+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
37
|
+
enum OrderStatus {
|
|
38
|
+
Pending,
|
|
39
|
+
Processing,
|
|
40
|
+
Completed,
|
|
41
|
+
Cancelled,
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
|
45
|
+
enum Priority {
|
|
46
|
+
Low,
|
|
47
|
+
Medium,
|
|
48
|
+
High,
|
|
49
|
+
Critical,
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
fn process_order(status: OrderStatus, priority: Priority) {
|
|
53
|
+
match status {
|
|
54
|
+
OrderStatus::Pending => { ... }
|
|
55
|
+
OrderStatus::Processing => { ... }
|
|
56
|
+
OrderStatus::Completed => { ... }
|
|
57
|
+
OrderStatus::Cancelled => { ... }
|
|
58
|
+
} // Exhaustive - compiler checks all cases
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Validated newtypes
|
|
62
|
+
struct Email(String);
|
|
63
|
+
struct PhoneNumber(String);
|
|
64
|
+
struct UserId(u64);
|
|
65
|
+
|
|
66
|
+
impl Email {
|
|
67
|
+
pub fn new(s: &str) -> Result<Self, ValidationError> {
|
|
68
|
+
if is_valid_email(s) {
|
|
69
|
+
Ok(Email(s.to_string()))
|
|
70
|
+
} else {
|
|
71
|
+
Err(ValidationError::InvalidEmail)
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
struct User {
|
|
77
|
+
email: Email, // Must be valid email
|
|
78
|
+
phone: PhoneNumber, // Must be valid phone
|
|
79
|
+
user_id: UserId, // Can't confuse with other IDs
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Compile errors catch mistakes
|
|
83
|
+
process_order(OrderStatus::Completed, Priority::High); // Clear and correct
|
|
84
|
+
process_order(Priority::High, OrderStatus::Pending); // Compile error!
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Parsing Strings to Types
|
|
88
|
+
|
|
89
|
+
```rust
|
|
90
|
+
use std::str::FromStr;
|
|
91
|
+
|
|
92
|
+
#[derive(Debug, Clone, Copy)]
|
|
93
|
+
enum OrderStatus {
|
|
94
|
+
Pending,
|
|
95
|
+
Processing,
|
|
96
|
+
Completed,
|
|
97
|
+
Cancelled,
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
impl FromStr for OrderStatus {
|
|
101
|
+
type Err = ParseError;
|
|
102
|
+
|
|
103
|
+
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
104
|
+
match s.to_lowercase().as_str() {
|
|
105
|
+
"pending" => Ok(OrderStatus::Pending),
|
|
106
|
+
"processing" => Ok(OrderStatus::Processing),
|
|
107
|
+
"completed" => Ok(OrderStatus::Completed),
|
|
108
|
+
"cancelled" | "canceled" => Ok(OrderStatus::Cancelled),
|
|
109
|
+
_ => Err(ParseError::UnknownStatus(s.to_string())),
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Parse at boundary, use types internally
|
|
115
|
+
fn handle_request(status_str: &str) -> Result<(), Error> {
|
|
116
|
+
let status: OrderStatus = status_str.parse()?; // Validate once
|
|
117
|
+
process_order(status); // Type-safe from here
|
|
118
|
+
Ok(())
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## With Serde
|
|
123
|
+
|
|
124
|
+
```rust
|
|
125
|
+
use serde::{Serialize, Deserialize};
|
|
126
|
+
|
|
127
|
+
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
128
|
+
#[serde(rename_all = "snake_case")]
|
|
129
|
+
enum Status {
|
|
130
|
+
Pending,
|
|
131
|
+
InProgress,
|
|
132
|
+
Completed,
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// JSON: {"status": "in_progress"}
|
|
136
|
+
// Deserialization validates automatically
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Error Messages
|
|
140
|
+
|
|
141
|
+
```rust
|
|
142
|
+
#[derive(Debug, Clone, Copy)]
|
|
143
|
+
enum Color {
|
|
144
|
+
Red,
|
|
145
|
+
Green,
|
|
146
|
+
Blue,
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
impl std::fmt::Display for Color {
|
|
150
|
+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
151
|
+
match self {
|
|
152
|
+
Color::Red => write!(f, "red"),
|
|
153
|
+
Color::Green => write!(f, "green"),
|
|
154
|
+
Color::Blue => write!(f, "blue"),
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Type-safe and displayable
|
|
160
|
+
println!("Selected color: {}", Color::Red);
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## See Also
|
|
164
|
+
|
|
165
|
+
- [api-newtype-safety](./api-newtype-safety.md) - Newtype pattern
|
|
166
|
+
- [api-parse-dont-validate](./api-parse-dont-validate.md) - Parse at boundaries
|
|
167
|
+
- [type-newtype-ids](./type-newtype-ids.md) - Type-safe IDs
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# anti-type-erasure
|
|
2
|
+
|
|
3
|
+
> Don't use Box<dyn Trait> when impl Trait works
|
|
4
|
+
|
|
5
|
+
## Why It Matters
|
|
6
|
+
|
|
7
|
+
`Box<dyn Trait>` (type erasure) introduces heap allocation and dynamic dispatch overhead. When you have a single concrete type or can use generics, `impl Trait` provides the same flexibility with zero overhead through monomorphization.
|
|
8
|
+
|
|
9
|
+
## Bad
|
|
10
|
+
|
|
11
|
+
```rust
|
|
12
|
+
// Unnecessary type erasure
|
|
13
|
+
fn get_iterator() -> Box<dyn Iterator<Item = i32>> {
|
|
14
|
+
Box::new((0..10).map(|x| x * 2))
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Boxing for no reason
|
|
18
|
+
fn make_handler() -> Box<dyn Fn(i32) -> i32> {
|
|
19
|
+
Box::new(|x| x + 1)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Vec of boxed trait objects when one type would do
|
|
23
|
+
fn get_validators() -> Vec<Box<dyn Validator>> {
|
|
24
|
+
vec![
|
|
25
|
+
Box::new(LengthValidator),
|
|
26
|
+
Box::new(RegexValidator),
|
|
27
|
+
]
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Good
|
|
32
|
+
|
|
33
|
+
```rust
|
|
34
|
+
// impl Trait - zero overhead, inlined
|
|
35
|
+
fn get_iterator() -> impl Iterator<Item = i32> {
|
|
36
|
+
(0..10).map(|x| x * 2)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// impl Fn - no boxing
|
|
40
|
+
fn make_handler() -> impl Fn(i32) -> i32 {
|
|
41
|
+
|x| x + 1
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// When mixed types are genuinely needed, Box is OK
|
|
45
|
+
fn get_validators() -> Vec<Box<dyn Validator>> {
|
|
46
|
+
// Actually different types at runtime - Box is appropriate
|
|
47
|
+
config.validators.iter()
|
|
48
|
+
.map(|v| v.create_validator())
|
|
49
|
+
.collect()
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## When to Use Box<dyn Trait>
|
|
54
|
+
|
|
55
|
+
Type erasure IS appropriate when:
|
|
56
|
+
|
|
57
|
+
```rust
|
|
58
|
+
// Heterogeneous collection of different types
|
|
59
|
+
let handlers: Vec<Box<dyn Handler>> = vec![
|
|
60
|
+
Box::new(LogHandler),
|
|
61
|
+
Box::new(MetricsHandler),
|
|
62
|
+
Box::new(AuthHandler),
|
|
63
|
+
];
|
|
64
|
+
|
|
65
|
+
// Type cannot be known at compile time
|
|
66
|
+
fn create_from_config(config: &Config) -> Box<dyn Database> {
|
|
67
|
+
match config.db_type {
|
|
68
|
+
DbType::Postgres => Box::new(PostgresDb::new()),
|
|
69
|
+
DbType::Sqlite => Box::new(SqliteDb::new()),
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Recursive types
|
|
74
|
+
struct Node {
|
|
75
|
+
value: i32,
|
|
76
|
+
children: Vec<Box<dyn NodeTrait>>,
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Breaking cycles in complex ownership
|
|
80
|
+
struct EventLoop {
|
|
81
|
+
handlers: Vec<Box<dyn EventHandler>>,
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Comparison
|
|
86
|
+
|
|
87
|
+
| Approach | Allocation | Dispatch | Binary Size |
|
|
88
|
+
|----------|------------|----------|-------------|
|
|
89
|
+
| `impl Trait` | Stack/inline | Static | Larger (monomorphization) |
|
|
90
|
+
| `Box<dyn Trait>` | Heap | Dynamic | Smaller |
|
|
91
|
+
| Generics `<T>` | Stack/inline | Static | Larger |
|
|
92
|
+
|
|
93
|
+
## impl Trait Positions
|
|
94
|
+
|
|
95
|
+
```rust
|
|
96
|
+
// Return position - caller doesn't need to know concrete type
|
|
97
|
+
fn process() -> impl Future<Output = Result> { }
|
|
98
|
+
|
|
99
|
+
// Argument position - like generics but simpler
|
|
100
|
+
fn handle(handler: impl Handler) { }
|
|
101
|
+
|
|
102
|
+
// Can't use in trait definitions (use associated types instead)
|
|
103
|
+
trait Processor {
|
|
104
|
+
type Output: Display; // Not impl Display
|
|
105
|
+
fn process(&self) -> Self::Output;
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## Pattern: Enum Instead of dyn
|
|
110
|
+
|
|
111
|
+
```rust
|
|
112
|
+
// Instead of Box<dyn Shape>
|
|
113
|
+
enum Shape {
|
|
114
|
+
Circle { radius: f64 },
|
|
115
|
+
Rectangle { width: f64, height: f64 },
|
|
116
|
+
Triangle { base: f64, height: f64 },
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
impl Shape {
|
|
120
|
+
fn area(&self) -> f64 {
|
|
121
|
+
match self {
|
|
122
|
+
Shape::Circle { radius } => PI * radius * radius,
|
|
123
|
+
Shape::Rectangle { width, height } => width * height,
|
|
124
|
+
Shape::Triangle { base, height } => 0.5 * base * height,
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## See Also
|
|
131
|
+
|
|
132
|
+
- [anti-over-abstraction](./anti-over-abstraction.md) - Excessive generics
|
|
133
|
+
- [type-generic-bounds](./type-generic-bounds.md) - Generic constraints
|
|
134
|
+
- [mem-box-large-variant](./mem-box-large-variant.md) - Boxing enum variants
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# anti-unwrap-abuse
|
|
2
|
+
|
|
3
|
+
> Don't use `.unwrap()` in production code
|
|
4
|
+
|
|
5
|
+
## Why It Matters
|
|
6
|
+
|
|
7
|
+
`.unwrap()` panics on `None` or `Err`, crashing your program. In production, this means lost data, failed requests, and unhappy users. It also makes debugging harder since panic messages often lack context.
|
|
8
|
+
|
|
9
|
+
## Bad
|
|
10
|
+
|
|
11
|
+
```rust
|
|
12
|
+
// Crashes if file doesn't exist
|
|
13
|
+
let content = std::fs::read_to_string("config.toml").unwrap();
|
|
14
|
+
|
|
15
|
+
// Crashes on invalid input
|
|
16
|
+
let num: i32 = user_input.parse().unwrap();
|
|
17
|
+
|
|
18
|
+
// Crashes if key missing
|
|
19
|
+
let value = map.get("key").unwrap();
|
|
20
|
+
|
|
21
|
+
// Crashes if channel closed
|
|
22
|
+
let msg = receiver.recv().unwrap();
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Good
|
|
26
|
+
|
|
27
|
+
```rust
|
|
28
|
+
// Propagate with ?
|
|
29
|
+
fn load_config() -> Result<Config, Error> {
|
|
30
|
+
let content = std::fs::read_to_string("config.toml")?;
|
|
31
|
+
Ok(toml::from_str(&content)?)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Provide default
|
|
35
|
+
let num: i32 = user_input.parse().unwrap_or(0);
|
|
36
|
+
|
|
37
|
+
// Handle missing key
|
|
38
|
+
let value = map.get("key").ok_or(Error::MissingKey)?;
|
|
39
|
+
|
|
40
|
+
// Or use if-let
|
|
41
|
+
if let Some(value) = map.get("key") {
|
|
42
|
+
process(value);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Channel with proper handling
|
|
46
|
+
match receiver.recv() {
|
|
47
|
+
Ok(msg) => handle(msg),
|
|
48
|
+
Err(_) => break, // Channel closed
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## When unwrap() Is Acceptable
|
|
53
|
+
|
|
54
|
+
```rust
|
|
55
|
+
// 1. Tests - panics are expected failures
|
|
56
|
+
#[test]
|
|
57
|
+
fn test_parse() {
|
|
58
|
+
let result = parse("valid").unwrap(); // OK in tests
|
|
59
|
+
assert_eq!(result, expected);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// 2. Const/static initialization (compile-time guaranteed)
|
|
63
|
+
static REGEX: Lazy<Regex> = Lazy::new(|| {
|
|
64
|
+
Regex::new(r"^\d+$").unwrap() // Known-valid pattern
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
// 3. After a check that guarantees success
|
|
68
|
+
if map.contains_key("key") {
|
|
69
|
+
let value = map.get("key").unwrap(); // Just checked
|
|
70
|
+
}
|
|
71
|
+
// Better: use if-let or entry API instead
|
|
72
|
+
|
|
73
|
+
// 4. Truly impossible cases with proof comment
|
|
74
|
+
let last = vec.pop().unwrap();
|
|
75
|
+
// OK only if you just checked !vec.is_empty()
|
|
76
|
+
// Better: use last() or pattern match
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Alternatives to unwrap()
|
|
80
|
+
|
|
81
|
+
```rust
|
|
82
|
+
// unwrap_or - provide default
|
|
83
|
+
let x = opt.unwrap_or(default);
|
|
84
|
+
|
|
85
|
+
// unwrap_or_default - use Default trait
|
|
86
|
+
let x = opt.unwrap_or_default();
|
|
87
|
+
|
|
88
|
+
// unwrap_or_else - compute default lazily
|
|
89
|
+
let x = opt.unwrap_or_else(|| expensive_default());
|
|
90
|
+
|
|
91
|
+
// ? operator - propagate errors
|
|
92
|
+
let x = opt.ok_or(Error::Missing)?;
|
|
93
|
+
|
|
94
|
+
// if let - handle Some/Ok case
|
|
95
|
+
if let Some(x) = opt {
|
|
96
|
+
use_x(x);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// match - handle all cases
|
|
100
|
+
match opt {
|
|
101
|
+
Some(x) => use_x(x),
|
|
102
|
+
None => handle_none(),
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// map - transform if present
|
|
106
|
+
let y = opt.map(|x| x + 1);
|
|
107
|
+
|
|
108
|
+
// and_then - chain fallible operations
|
|
109
|
+
let z = opt.and_then(|x| x.checked_add(1));
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## expect() Is Slightly Better
|
|
113
|
+
|
|
114
|
+
```rust
|
|
115
|
+
// unwrap() - no context
|
|
116
|
+
let file = File::open(path).unwrap();
|
|
117
|
+
// Panics with: "called `Result::unwrap()` on an `Err` value: Os { code: 2, ... }"
|
|
118
|
+
|
|
119
|
+
// expect() - adds context
|
|
120
|
+
let file = File::open(path)
|
|
121
|
+
.expect("config file should exist at startup");
|
|
122
|
+
// Panics with: "config file should exist at startup: Os { code: 2, ... }"
|
|
123
|
+
|
|
124
|
+
// But still use only for invariants, not error handling
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Clippy Lint
|
|
128
|
+
|
|
129
|
+
```rust
|
|
130
|
+
// Enable these lints to catch unwrap usage:
|
|
131
|
+
#![warn(clippy::unwrap_used)]
|
|
132
|
+
#![warn(clippy::expect_used)] // Stricter
|
|
133
|
+
|
|
134
|
+
// Or per-function:
|
|
135
|
+
#[allow(clippy::unwrap_used)]
|
|
136
|
+
fn tests_only() { }
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## See Also
|
|
140
|
+
|
|
141
|
+
- [err-question-mark](err-question-mark.md) - Use ? for propagation
|
|
142
|
+
- [err-result-over-panic](err-result-over-panic.md) - Return Result instead of panicking
|
|
143
|
+
- [anti-expect-lazy](anti-expect-lazy.md) - Don't use expect for recoverable errors
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# anti-vec-for-slice
|
|
2
|
+
|
|
3
|
+
> Don't accept &Vec<T> when &[T] works
|
|
4
|
+
|
|
5
|
+
## Why It Matters
|
|
6
|
+
|
|
7
|
+
`&Vec<T>` is strictly less flexible than `&[T]`. A slice can be created from `Vec`, arrays, and other slice-like types. Accepting `&Vec<T>` forces callers to have exactly a `Vec`, preventing them from using arrays, slices, or other collections.
|
|
8
|
+
|
|
9
|
+
## Bad
|
|
10
|
+
|
|
11
|
+
```rust
|
|
12
|
+
// Forces callers to have a Vec
|
|
13
|
+
fn sum(numbers: &Vec<i32>) -> i32 {
|
|
14
|
+
numbers.iter().sum()
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Caller must allocate
|
|
18
|
+
let arr = [1, 2, 3, 4, 5];
|
|
19
|
+
sum(&arr.to_vec()); // Unnecessary allocation
|
|
20
|
+
|
|
21
|
+
// Slice won't work
|
|
22
|
+
let slice: &[i32] = &[1, 2, 3];
|
|
23
|
+
// sum(slice); // Error: expected &Vec<i32>
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Good
|
|
27
|
+
|
|
28
|
+
```rust
|
|
29
|
+
// Accept slice - works with Vec, arrays, slices
|
|
30
|
+
fn sum(numbers: &[i32]) -> i32 {
|
|
31
|
+
numbers.iter().sum()
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// All these work
|
|
35
|
+
sum(&[1, 2, 3, 4, 5]); // Array
|
|
36
|
+
sum(&vec![1, 2, 3]); // Vec
|
|
37
|
+
sum(&numbers[1..3]); // Slice of slice
|
|
38
|
+
sum(numbers.as_slice()); // Explicit slice
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Deref Coercion
|
|
42
|
+
|
|
43
|
+
`Vec<T>` implements `Deref<Target = [T]>`, so `&Vec<T>` automatically coerces to `&[T]`:
|
|
44
|
+
|
|
45
|
+
```rust
|
|
46
|
+
fn takes_slice(s: &[i32]) { }
|
|
47
|
+
|
|
48
|
+
let vec = vec![1, 2, 3];
|
|
49
|
+
takes_slice(&vec); // &Vec<i32> -> &[i32] via Deref
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Mutable Slices
|
|
53
|
+
|
|
54
|
+
Same applies to `&mut`:
|
|
55
|
+
|
|
56
|
+
```rust
|
|
57
|
+
// Bad
|
|
58
|
+
fn double(numbers: &mut Vec<i32>) {
|
|
59
|
+
for n in numbers.iter_mut() {
|
|
60
|
+
*n *= 2;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Good
|
|
65
|
+
fn double(numbers: &mut [i32]) {
|
|
66
|
+
for n in numbers.iter_mut() {
|
|
67
|
+
*n *= 2;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## When to Accept &Vec<T>
|
|
73
|
+
|
|
74
|
+
Rarely. Only when you need Vec-specific operations:
|
|
75
|
+
|
|
76
|
+
```rust
|
|
77
|
+
fn needs_capacity(v: &Vec<i32>) -> usize {
|
|
78
|
+
v.capacity() // Only Vec has capacity
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
fn might_grow(v: &mut Vec<i32>) {
|
|
82
|
+
v.push(42); // Slice can't push
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Pattern: Accepting Multiple Types
|
|
87
|
+
|
|
88
|
+
```rust
|
|
89
|
+
// Accept anything that can be viewed as a slice
|
|
90
|
+
fn process<T: AsRef<[u8]>>(data: T) {
|
|
91
|
+
let bytes: &[u8] = data.as_ref();
|
|
92
|
+
// ...
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
process(&[1u8, 2, 3]); // Array
|
|
96
|
+
process(vec![1u8, 2, 3]); // Vec
|
|
97
|
+
process(&some_vec); // &Vec
|
|
98
|
+
process(b"bytes"); // Byte string
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Similar Anti-patterns
|
|
102
|
+
|
|
103
|
+
| Anti-pattern | Better |
|
|
104
|
+
|--------------|--------|
|
|
105
|
+
| `&Vec<T>` | `&[T]` |
|
|
106
|
+
| `&String` | `&str` |
|
|
107
|
+
| `&PathBuf` | `&Path` |
|
|
108
|
+
| `&Box<T>` | `&T` |
|
|
109
|
+
|
|
110
|
+
## Clippy Detection
|
|
111
|
+
|
|
112
|
+
```toml
|
|
113
|
+
[lints.clippy]
|
|
114
|
+
ptr_arg = "warn" # Catches &Vec, &String, &PathBuf
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## See Also
|
|
118
|
+
|
|
119
|
+
- [anti-string-for-str](./anti-string-for-str.md) - Similar for String
|
|
120
|
+
- [own-slice-over-vec](./own-slice-over-vec.md) - Slice patterns
|
|
121
|
+
- [api-impl-asref](./api-impl-asref.md) - AsRef pattern
|