agy-superpowers 5.2.1 → 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/patches/skills-patches.md +23 -0
- package/template/agent/rules/scratch-scripts.md +37 -0
- package/template/agent/rules/superpowers.md +6 -50
- package/template/agent/skills/brainstorming/SKILL.md +4 -3
- package/template/agent/skills/brainstorming/visual-companion.md +2 -3
- package/template/agent/skills/finishing-a-development-branch/SKILL.md +11 -16
- package/template/agent/skills/subagent-driven-development/SKILL.md +16 -0
- package/template/agent/skills/subagent-driven-development/implementer-prompt.md +4 -3
- package/template/agent/skills/using-git-worktrees/SKILL.md +3 -2
- package/template/agent/skills/using-superpowers/SKILL.md +8 -6
- package/template/agent/skills/using-superpowers/references/copilot-tools.md +52 -0
- package/template/agent/skills/writing-plans/SKILL.md +5 -3
- package/template/agent/skills/writing-skills/SKILL.md +1 -1
- package/template/agent/superpowers-version.json +2 -2
- package/template/agent/tmp/agent-config-backup.yml +9 -0
- package/template/agent/skills/ai-integrated-product/SKILL.md +0 -57
- package/template/agent/skills/analytics-setup/SKILL.md +0 -51
- package/template/agent/skills/api-design/SKILL.md +0 -193
- package/template/agent/skills/app-store-optimizer/SKILL.md +0 -127
- package/template/agent/skills/auth-and-identity/SKILL.md +0 -167
- package/template/agent/skills/backend-developer/SKILL.md +0 -148
- package/template/agent/skills/bootstrapper-finance/SKILL.md +0 -55
- package/template/agent/skills/chrome-extension-developer/SKILL.md +0 -53
- package/template/agent/skills/community-manager/SKILL.md +0 -115
- package/template/agent/skills/content-marketer/SKILL.md +0 -111
- package/template/agent/skills/conversion-optimizer/SKILL.md +0 -142
- package/template/agent/skills/cto-architect/SKILL.md +0 -133
- package/template/agent/skills/customer-success-manager/SKILL.md +0 -126
- package/template/agent/skills/data-analyst/SKILL.md +0 -147
- package/template/agent/skills/devops-engineer/SKILL.md +0 -117
- package/template/agent/skills/email-infrastructure/SKILL.md +0 -164
- package/template/agent/skills/game-design/SKILL.md +0 -194
- package/template/agent/skills/game-developer/SKILL.md +0 -175
- package/template/agent/skills/growth-hacker/SKILL.md +0 -122
- package/template/agent/skills/idea-validator/SKILL.md +0 -55
- package/template/agent/skills/indie-legal/SKILL.md +0 -53
- package/template/agent/skills/influencer-marketer/SKILL.md +0 -141
- package/template/agent/skills/landing-page-builder/SKILL.md +0 -59
- package/template/agent/skills/launch-strategist/SKILL.md +0 -62
- package/template/agent/skills/market-researcher/SKILL.md +0 -53
- package/template/agent/skills/micro-saas-builder/SKILL.md +0 -56
- package/template/agent/skills/monetization-strategist/SKILL.md +0 -119
- package/template/agent/skills/paid-acquisition-specialist/SKILL.md +0 -119
- package/template/agent/skills/pricing-psychologist/SKILL.md +0 -58
- package/template/agent/skills/real-time-features/SKILL.md +0 -194
- package/template/agent/skills/retention-specialist/SKILL.md +0 -123
- package/template/agent/skills/rust-developer/SKILL.md +0 -281
- package/template/agent/skills/rust-developer/references/rust-rules/_sections.md +0 -231
- package/template/agent/skills/rust-developer/references/rust-rules/anti-clone-excessive.md +0 -124
- package/template/agent/skills/rust-developer/references/rust-rules/anti-collect-intermediate.md +0 -131
- package/template/agent/skills/rust-developer/references/rust-rules/anti-empty-catch.md +0 -132
- package/template/agent/skills/rust-developer/references/rust-rules/anti-expect-lazy.md +0 -95
- package/template/agent/skills/rust-developer/references/rust-rules/anti-format-hot-path.md +0 -141
- package/template/agent/skills/rust-developer/references/rust-rules/anti-index-over-iter.md +0 -125
- package/template/agent/skills/rust-developer/references/rust-rules/anti-lock-across-await.md +0 -127
- package/template/agent/skills/rust-developer/references/rust-rules/anti-over-abstraction.md +0 -120
- package/template/agent/skills/rust-developer/references/rust-rules/anti-panic-expected.md +0 -131
- package/template/agent/skills/rust-developer/references/rust-rules/anti-premature-optimize.md +0 -156
- package/template/agent/skills/rust-developer/references/rust-rules/anti-string-for-str.md +0 -122
- package/template/agent/skills/rust-developer/references/rust-rules/anti-stringly-typed.md +0 -167
- package/template/agent/skills/rust-developer/references/rust-rules/anti-type-erasure.md +0 -134
- package/template/agent/skills/rust-developer/references/rust-rules/anti-unwrap-abuse.md +0 -143
- package/template/agent/skills/rust-developer/references/rust-rules/anti-vec-for-slice.md +0 -121
- package/template/agent/skills/rust-developer/references/rust-rules/api-builder-must-use.md +0 -143
- package/template/agent/skills/rust-developer/references/rust-rules/api-builder-pattern.md +0 -187
- package/template/agent/skills/rust-developer/references/rust-rules/api-common-traits.md +0 -165
- package/template/agent/skills/rust-developer/references/rust-rules/api-default-impl.md +0 -177
- package/template/agent/skills/rust-developer/references/rust-rules/api-extension-trait.md +0 -163
- package/template/agent/skills/rust-developer/references/rust-rules/api-from-not-into.md +0 -146
- package/template/agent/skills/rust-developer/references/rust-rules/api-impl-asref.md +0 -142
- package/template/agent/skills/rust-developer/references/rust-rules/api-impl-into.md +0 -160
- package/template/agent/skills/rust-developer/references/rust-rules/api-must-use.md +0 -125
- package/template/agent/skills/rust-developer/references/rust-rules/api-newtype-safety.md +0 -162
- package/template/agent/skills/rust-developer/references/rust-rules/api-non-exhaustive.md +0 -177
- package/template/agent/skills/rust-developer/references/rust-rules/api-parse-dont-validate.md +0 -184
- package/template/agent/skills/rust-developer/references/rust-rules/api-sealed-trait.md +0 -168
- package/template/agent/skills/rust-developer/references/rust-rules/api-serde-optional.md +0 -182
- package/template/agent/skills/rust-developer/references/rust-rules/api-typestate.md +0 -199
- package/template/agent/skills/rust-developer/references/rust-rules/async-bounded-channel.md +0 -175
- package/template/agent/skills/rust-developer/references/rust-rules/async-broadcast-pubsub.md +0 -185
- package/template/agent/skills/rust-developer/references/rust-rules/async-cancellation-token.md +0 -203
- package/template/agent/skills/rust-developer/references/rust-rules/async-clone-before-await.md +0 -171
- package/template/agent/skills/rust-developer/references/rust-rules/async-join-parallel.md +0 -158
- package/template/agent/skills/rust-developer/references/rust-rules/async-joinset-structured.md +0 -195
- package/template/agent/skills/rust-developer/references/rust-rules/async-mpsc-queue.md +0 -171
- package/template/agent/skills/rust-developer/references/rust-rules/async-no-lock-await.md +0 -156
- package/template/agent/skills/rust-developer/references/rust-rules/async-oneshot-response.md +0 -191
- package/template/agent/skills/rust-developer/references/rust-rules/async-select-racing.md +0 -198
- package/template/agent/skills/rust-developer/references/rust-rules/async-spawn-blocking.md +0 -154
- package/template/agent/skills/rust-developer/references/rust-rules/async-tokio-fs.md +0 -167
- package/template/agent/skills/rust-developer/references/rust-rules/async-tokio-runtime.md +0 -169
- package/template/agent/skills/rust-developer/references/rust-rules/async-try-join.md +0 -172
- package/template/agent/skills/rust-developer/references/rust-rules/async-watch-latest.md +0 -189
- package/template/agent/skills/rust-developer/references/rust-rules/doc-all-public.md +0 -113
- package/template/agent/skills/rust-developer/references/rust-rules/doc-cargo-metadata.md +0 -147
- package/template/agent/skills/rust-developer/references/rust-rules/doc-errors-section.md +0 -122
- package/template/agent/skills/rust-developer/references/rust-rules/doc-examples-section.md +0 -161
- package/template/agent/skills/rust-developer/references/rust-rules/doc-hidden-setup.md +0 -149
- package/template/agent/skills/rust-developer/references/rust-rules/doc-intra-links.md +0 -138
- package/template/agent/skills/rust-developer/references/rust-rules/doc-link-types.md +0 -169
- package/template/agent/skills/rust-developer/references/rust-rules/doc-module-inner.md +0 -116
- package/template/agent/skills/rust-developer/references/rust-rules/doc-panics-section.md +0 -128
- package/template/agent/skills/rust-developer/references/rust-rules/doc-question-mark.md +0 -136
- package/template/agent/skills/rust-developer/references/rust-rules/doc-safety-section.md +0 -131
- package/template/agent/skills/rust-developer/references/rust-rules/err-anyhow-app.md +0 -179
- package/template/agent/skills/rust-developer/references/rust-rules/err-context-chain.md +0 -144
- package/template/agent/skills/rust-developer/references/rust-rules/err-custom-type.md +0 -152
- package/template/agent/skills/rust-developer/references/rust-rules/err-doc-errors.md +0 -145
- package/template/agent/skills/rust-developer/references/rust-rules/err-expect-bugs-only.md +0 -133
- package/template/agent/skills/rust-developer/references/rust-rules/err-from-impl.md +0 -152
- package/template/agent/skills/rust-developer/references/rust-rules/err-lowercase-msg.md +0 -124
- package/template/agent/skills/rust-developer/references/rust-rules/err-no-unwrap-prod.md +0 -115
- package/template/agent/skills/rust-developer/references/rust-rules/err-question-mark.md +0 -151
- package/template/agent/skills/rust-developer/references/rust-rules/err-result-over-panic.md +0 -130
- package/template/agent/skills/rust-developer/references/rust-rules/err-source-chain.md +0 -155
- package/template/agent/skills/rust-developer/references/rust-rules/err-thiserror-lib.md +0 -171
- package/template/agent/skills/rust-developer/references/rust-rules/lint-cargo-metadata.md +0 -138
- package/template/agent/skills/rust-developer/references/rust-rules/lint-deny-correctness.md +0 -107
- package/template/agent/skills/rust-developer/references/rust-rules/lint-missing-docs.md +0 -154
- package/template/agent/skills/rust-developer/references/rust-rules/lint-pedantic-selective.md +0 -118
- package/template/agent/skills/rust-developer/references/rust-rules/lint-rustfmt-check.md +0 -157
- package/template/agent/skills/rust-developer/references/rust-rules/lint-unsafe-doc.md +0 -133
- package/template/agent/skills/rust-developer/references/rust-rules/lint-warn-complexity.md +0 -131
- package/template/agent/skills/rust-developer/references/rust-rules/lint-warn-perf.md +0 -136
- package/template/agent/skills/rust-developer/references/rust-rules/lint-warn-style.md +0 -135
- package/template/agent/skills/rust-developer/references/rust-rules/lint-warn-suspicious.md +0 -122
- package/template/agent/skills/rust-developer/references/rust-rules/lint-workspace-lints.md +0 -172
- package/template/agent/skills/rust-developer/references/rust-rules/mem-arena-allocator.md +0 -168
- package/template/agent/skills/rust-developer/references/rust-rules/mem-arrayvec.md +0 -142
- package/template/agent/skills/rust-developer/references/rust-rules/mem-assert-type-size.md +0 -168
- package/template/agent/skills/rust-developer/references/rust-rules/mem-avoid-format.md +0 -147
- package/template/agent/skills/rust-developer/references/rust-rules/mem-box-large-variant.md +0 -158
- package/template/agent/skills/rust-developer/references/rust-rules/mem-boxed-slice.md +0 -139
- package/template/agent/skills/rust-developer/references/rust-rules/mem-clone-from.md +0 -147
- package/template/agent/skills/rust-developer/references/rust-rules/mem-compact-string.md +0 -149
- package/template/agent/skills/rust-developer/references/rust-rules/mem-reuse-collections.md +0 -174
- package/template/agent/skills/rust-developer/references/rust-rules/mem-smaller-integers.md +0 -159
- package/template/agent/skills/rust-developer/references/rust-rules/mem-smallvec.md +0 -138
- package/template/agent/skills/rust-developer/references/rust-rules/mem-thinvec.md +0 -142
- package/template/agent/skills/rust-developer/references/rust-rules/mem-with-capacity.md +0 -156
- package/template/agent/skills/rust-developer/references/rust-rules/mem-write-over-format.md +0 -172
- package/template/agent/skills/rust-developer/references/rust-rules/mem-zero-copy.md +0 -164
- package/template/agent/skills/rust-developer/references/rust-rules/name-acronym-word.md +0 -99
- package/template/agent/skills/rust-developer/references/rust-rules/name-as-free.md +0 -104
- package/template/agent/skills/rust-developer/references/rust-rules/name-consts-screaming.md +0 -94
- package/template/agent/skills/rust-developer/references/rust-rules/name-crate-no-rs.md +0 -78
- package/template/agent/skills/rust-developer/references/rust-rules/name-funcs-snake.md +0 -76
- package/template/agent/skills/rust-developer/references/rust-rules/name-into-ownership.md +0 -123
- package/template/agent/skills/rust-developer/references/rust-rules/name-is-has-bool.md +0 -127
- package/template/agent/skills/rust-developer/references/rust-rules/name-iter-convention.md +0 -129
- package/template/agent/skills/rust-developer/references/rust-rules/name-iter-method.md +0 -131
- package/template/agent/skills/rust-developer/references/rust-rules/name-iter-type-match.md +0 -142
- package/template/agent/skills/rust-developer/references/rust-rules/name-lifetime-short.md +0 -86
- package/template/agent/skills/rust-developer/references/rust-rules/name-no-get-prefix.md +0 -154
- package/template/agent/skills/rust-developer/references/rust-rules/name-to-expensive.md +0 -118
- package/template/agent/skills/rust-developer/references/rust-rules/name-type-param-single.md +0 -92
- package/template/agent/skills/rust-developer/references/rust-rules/name-types-camel.md +0 -65
- package/template/agent/skills/rust-developer/references/rust-rules/name-variants-camel.md +0 -101
- package/template/agent/skills/rust-developer/references/rust-rules/opt-bounds-check.md +0 -161
- package/template/agent/skills/rust-developer/references/rust-rules/opt-cache-friendly.md +0 -187
- package/template/agent/skills/rust-developer/references/rust-rules/opt-codegen-units.md +0 -142
- package/template/agent/skills/rust-developer/references/rust-rules/opt-cold-unlikely.md +0 -152
- package/template/agent/skills/rust-developer/references/rust-rules/opt-inline-always-rare.md +0 -141
- package/template/agent/skills/rust-developer/references/rust-rules/opt-inline-never-cold.md +0 -181
- package/template/agent/skills/rust-developer/references/rust-rules/opt-inline-small.md +0 -160
- package/template/agent/skills/rust-developer/references/rust-rules/opt-likely-hint.md +0 -171
- package/template/agent/skills/rust-developer/references/rust-rules/opt-lto-release.md +0 -130
- package/template/agent/skills/rust-developer/references/rust-rules/opt-pgo-profile.md +0 -167
- package/template/agent/skills/rust-developer/references/rust-rules/opt-simd-portable.md +0 -144
- package/template/agent/skills/rust-developer/references/rust-rules/opt-target-cpu.md +0 -154
- package/template/agent/skills/rust-developer/references/rust-rules/own-arc-shared.md +0 -141
- package/template/agent/skills/rust-developer/references/rust-rules/own-borrow-over-clone.md +0 -95
- package/template/agent/skills/rust-developer/references/rust-rules/own-clone-explicit.md +0 -135
- package/template/agent/skills/rust-developer/references/rust-rules/own-copy-small.md +0 -124
- package/template/agent/skills/rust-developer/references/rust-rules/own-cow-conditional.md +0 -135
- package/template/agent/skills/rust-developer/references/rust-rules/own-lifetime-elision.md +0 -134
- package/template/agent/skills/rust-developer/references/rust-rules/own-move-large.md +0 -134
- package/template/agent/skills/rust-developer/references/rust-rules/own-mutex-interior.md +0 -105
- package/template/agent/skills/rust-developer/references/rust-rules/own-rc-single-thread.md +0 -65
- package/template/agent/skills/rust-developer/references/rust-rules/own-refcell-interior.md +0 -97
- package/template/agent/skills/rust-developer/references/rust-rules/own-rwlock-readers.md +0 -122
- package/template/agent/skills/rust-developer/references/rust-rules/own-slice-over-vec.md +0 -119
- package/template/agent/skills/rust-developer/references/rust-rules/perf-black-box-bench.md +0 -153
- package/template/agent/skills/rust-developer/references/rust-rules/perf-chain-avoid.md +0 -136
- package/template/agent/skills/rust-developer/references/rust-rules/perf-collect-into.md +0 -133
- package/template/agent/skills/rust-developer/references/rust-rules/perf-collect-once.md +0 -120
- package/template/agent/skills/rust-developer/references/rust-rules/perf-drain-reuse.md +0 -137
- package/template/agent/skills/rust-developer/references/rust-rules/perf-entry-api.md +0 -134
- package/template/agent/skills/rust-developer/references/rust-rules/perf-extend-batch.md +0 -150
- package/template/agent/skills/rust-developer/references/rust-rules/perf-iter-lazy.md +0 -123
- package/template/agent/skills/rust-developer/references/rust-rules/perf-iter-over-index.md +0 -113
- package/template/agent/skills/rust-developer/references/rust-rules/perf-profile-first.md +0 -175
- package/template/agent/skills/rust-developer/references/rust-rules/perf-release-profile.md +0 -149
- package/template/agent/skills/rust-developer/references/rust-rules/proj-bin-dir.md +0 -142
- package/template/agent/skills/rust-developer/references/rust-rules/proj-flat-small.md +0 -133
- package/template/agent/skills/rust-developer/references/rust-rules/proj-lib-main-split.md +0 -148
- package/template/agent/skills/rust-developer/references/rust-rules/proj-mod-by-feature.md +0 -130
- package/template/agent/skills/rust-developer/references/rust-rules/proj-mod-rs-dir.md +0 -120
- package/template/agent/skills/rust-developer/references/rust-rules/proj-prelude-module.md +0 -155
- package/template/agent/skills/rust-developer/references/rust-rules/proj-pub-crate-internal.md +0 -139
- package/template/agent/skills/rust-developer/references/rust-rules/proj-pub-super-parent.md +0 -135
- package/template/agent/skills/rust-developer/references/rust-rules/proj-pub-use-reexport.md +0 -162
- package/template/agent/skills/rust-developer/references/rust-rules/proj-workspace-deps.md +0 -186
- package/template/agent/skills/rust-developer/references/rust-rules/proj-workspace-large.md +0 -162
- package/template/agent/skills/rust-developer/references/rust-rules/test-arrange-act-assert.md +0 -160
- package/template/agent/skills/rust-developer/references/rust-rules/test-cfg-test-module.md +0 -151
- package/template/agent/skills/rust-developer/references/rust-rules/test-criterion-bench.md +0 -171
- package/template/agent/skills/rust-developer/references/rust-rules/test-descriptive-names.md +0 -142
- package/template/agent/skills/rust-developer/references/rust-rules/test-doctest-examples.md +0 -168
- package/template/agent/skills/rust-developer/references/rust-rules/test-fixture-raii.md +0 -151
- package/template/agent/skills/rust-developer/references/rust-rules/test-integration-dir.md +0 -144
- package/template/agent/skills/rust-developer/references/rust-rules/test-mock-traits.md +0 -189
- package/template/agent/skills/rust-developer/references/rust-rules/test-mockall-mocking.md +0 -226
- package/template/agent/skills/rust-developer/references/rust-rules/test-proptest-properties.md +0 -161
- package/template/agent/skills/rust-developer/references/rust-rules/test-should-panic.md +0 -130
- package/template/agent/skills/rust-developer/references/rust-rules/test-tokio-async.md +0 -154
- package/template/agent/skills/rust-developer/references/rust-rules/test-use-super.md +0 -127
- package/template/agent/skills/rust-developer/references/rust-rules/type-enum-states.md +0 -154
- package/template/agent/skills/rust-developer/references/rust-rules/type-generic-bounds.md +0 -142
- package/template/agent/skills/rust-developer/references/rust-rules/type-never-diverge.md +0 -146
- package/template/agent/skills/rust-developer/references/rust-rules/type-newtype-ids.md +0 -160
- package/template/agent/skills/rust-developer/references/rust-rules/type-newtype-validated.md +0 -159
- package/template/agent/skills/rust-developer/references/rust-rules/type-no-stringly.md +0 -144
- package/template/agent/skills/rust-developer/references/rust-rules/type-option-nullable.md +0 -137
- package/template/agent/skills/rust-developer/references/rust-rules/type-phantom-marker.md +0 -188
- package/template/agent/skills/rust-developer/references/rust-rules/type-repr-transparent.md +0 -143
- package/template/agent/skills/rust-developer/references/rust-rules/type-result-fallible.md +0 -131
- package/template/agent/skills/saas-architect/SKILL.md +0 -139
- package/template/agent/skills/security-engineer/SKILL.md +0 -133
- package/template/agent/skills/seo-specialist/SKILL.md +0 -130
- package/template/agent/skills/solo-founder-ops/SKILL.md +0 -56
|
@@ -1,179 +0,0 @@
|
|
|
1
|
-
# err-anyhow-app
|
|
2
|
-
|
|
3
|
-
> Use `anyhow` for application error handling
|
|
4
|
-
|
|
5
|
-
## Why It Matters
|
|
6
|
-
|
|
7
|
-
Applications often don't need typed errors - they just need to report what went wrong with good context. `anyhow` provides easy error handling with context chaining, backtraces, and conversion from any error type.
|
|
8
|
-
|
|
9
|
-
## Bad
|
|
10
|
-
|
|
11
|
-
```rust
|
|
12
|
-
// Tedious type management
|
|
13
|
-
fn load_config() -> Result<Config, Box<dyn std::error::Error>> {
|
|
14
|
-
let path = find_config()?; // Returns FindError
|
|
15
|
-
let content = std::fs::read_to_string(&path)?; // Returns io::Error
|
|
16
|
-
let config: Config = toml::from_str(&content)?; // Returns toml::Error
|
|
17
|
-
validate(&config)?; // Returns ValidationError
|
|
18
|
-
Ok(config)
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
// No context - hard to debug
|
|
22
|
-
fn process() -> Result<(), Box<dyn std::error::Error>> {
|
|
23
|
-
let data = fetch()?; // Which fetch failed?
|
|
24
|
-
transform(data)?; // What was being transformed?
|
|
25
|
-
save()?; // Where was it saving to?
|
|
26
|
-
Ok(())
|
|
27
|
-
}
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
## Good
|
|
31
|
-
|
|
32
|
-
```rust
|
|
33
|
-
use anyhow::{Context, Result};
|
|
34
|
-
|
|
35
|
-
fn load_config() -> Result<Config> {
|
|
36
|
-
let path = find_config()
|
|
37
|
-
.context("failed to locate config file")?;
|
|
38
|
-
|
|
39
|
-
let content = std::fs::read_to_string(&path)
|
|
40
|
-
.with_context(|| format!("failed to read config from {}", path.display()))?;
|
|
41
|
-
|
|
42
|
-
let config: Config = toml::from_str(&content)
|
|
43
|
-
.context("failed to parse config as TOML")?;
|
|
44
|
-
|
|
45
|
-
validate(&config)
|
|
46
|
-
.context("config validation failed")?;
|
|
47
|
-
|
|
48
|
-
Ok(config)
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// Error message: "config validation failed: field 'port' must be > 0"
|
|
52
|
-
// Full chain preserved for debugging
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
## Key Features
|
|
56
|
-
|
|
57
|
-
```rust
|
|
58
|
-
use anyhow::{anyhow, bail, ensure, Context, Result};
|
|
59
|
-
|
|
60
|
-
fn example() -> Result<()> {
|
|
61
|
-
// Create ad-hoc errors
|
|
62
|
-
let err = anyhow!("something went wrong");
|
|
63
|
-
|
|
64
|
-
// Early return with error
|
|
65
|
-
bail!("aborting due to {}", reason);
|
|
66
|
-
|
|
67
|
-
// Assert with error
|
|
68
|
-
ensure!(condition, "condition was false");
|
|
69
|
-
|
|
70
|
-
// Add context to any error
|
|
71
|
-
risky_operation()
|
|
72
|
-
.context("risky operation failed")?;
|
|
73
|
-
|
|
74
|
-
// Dynamic context
|
|
75
|
-
fetch(url)
|
|
76
|
-
.with_context(|| format!("failed to fetch {}", url))?;
|
|
77
|
-
|
|
78
|
-
Ok(())
|
|
79
|
-
}
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
## Main Function Pattern
|
|
83
|
-
|
|
84
|
-
```rust
|
|
85
|
-
use anyhow::Result;
|
|
86
|
-
|
|
87
|
-
fn main() -> Result<()> {
|
|
88
|
-
let config = load_config()?;
|
|
89
|
-
run_app(config)?;
|
|
90
|
-
Ok(())
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
// Or with custom exit handling
|
|
94
|
-
fn main() {
|
|
95
|
-
if let Err(e) = run() {
|
|
96
|
-
eprintln!("Error: {:#}", e); // Pretty-print with causes
|
|
97
|
-
std::process::exit(1);
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
fn run() -> Result<()> {
|
|
102
|
-
// Application logic
|
|
103
|
-
Ok(())
|
|
104
|
-
}
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
## Error Display Formats
|
|
108
|
-
|
|
109
|
-
```rust
|
|
110
|
-
use anyhow::Result;
|
|
111
|
-
|
|
112
|
-
fn show_error(err: anyhow::Error) {
|
|
113
|
-
// Just the top-level message
|
|
114
|
-
println!("{}", err);
|
|
115
|
-
// "config validation failed"
|
|
116
|
-
|
|
117
|
-
// With cause chain (# alternate format)
|
|
118
|
-
println!("{:#}", err);
|
|
119
|
-
// "config validation failed: field 'port' must be > 0"
|
|
120
|
-
|
|
121
|
-
// Debug format with backtrace
|
|
122
|
-
println!("{:?}", err);
|
|
123
|
-
// Full backtrace if RUST_BACKTRACE=1
|
|
124
|
-
|
|
125
|
-
// Iterate through cause chain
|
|
126
|
-
for cause in err.chain() {
|
|
127
|
-
println!("Caused by: {}", cause);
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
## Combining with thiserror
|
|
133
|
-
|
|
134
|
-
```rust
|
|
135
|
-
// In your library crate - typed errors
|
|
136
|
-
use thiserror::Error;
|
|
137
|
-
|
|
138
|
-
#[derive(Error, Debug)]
|
|
139
|
-
pub enum ApiError {
|
|
140
|
-
#[error("rate limited")]
|
|
141
|
-
RateLimited,
|
|
142
|
-
#[error("not found: {0}")]
|
|
143
|
-
NotFound(String),
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// In your application - anyhow for handling
|
|
147
|
-
use anyhow::{Context, Result};
|
|
148
|
-
|
|
149
|
-
fn fetch_user(id: u64) -> Result<User> {
|
|
150
|
-
api::get_user(id)
|
|
151
|
-
.with_context(|| format!("failed to fetch user {}", id))
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
// Can still downcast if needed
|
|
155
|
-
fn handle_error(err: anyhow::Error) {
|
|
156
|
-
if let Some(api_err) = err.downcast_ref::<ApiError>() {
|
|
157
|
-
match api_err {
|
|
158
|
-
ApiError::RateLimited => wait_and_retry(),
|
|
159
|
-
ApiError::NotFound(id) => log_missing(id),
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
```
|
|
164
|
-
|
|
165
|
-
## When to Use Which
|
|
166
|
-
|
|
167
|
-
| Situation | Use |
|
|
168
|
-
|-----------|-----|
|
|
169
|
-
| Library public API | `thiserror` |
|
|
170
|
-
| Application code | `anyhow` |
|
|
171
|
-
| CLI tools | `anyhow` |
|
|
172
|
-
| Internal library code | Either |
|
|
173
|
-
| Need to match error variants | `thiserror` |
|
|
174
|
-
| Just need to report errors | `anyhow` |
|
|
175
|
-
|
|
176
|
-
## See Also
|
|
177
|
-
|
|
178
|
-
- [err-thiserror-lib](err-thiserror-lib.md) - Use thiserror for libraries
|
|
179
|
-
- [err-context-chain](err-context-chain.md) - Add context to errors
|
|
@@ -1,144 +0,0 @@
|
|
|
1
|
-
# err-context-chain
|
|
2
|
-
|
|
3
|
-
> Add context with `.context()` or `.with_context()`
|
|
4
|
-
|
|
5
|
-
## Why It Matters
|
|
6
|
-
|
|
7
|
-
Raw errors often lack information about what operation failed. Adding context creates an error chain that tells the full story: what you were trying to do, and why it failed.
|
|
8
|
-
|
|
9
|
-
## Bad
|
|
10
|
-
|
|
11
|
-
```rust
|
|
12
|
-
// Raw error - no context
|
|
13
|
-
fn load_user(id: u64) -> Result<User, Error> {
|
|
14
|
-
let path = format!("users/{}.json", id);
|
|
15
|
-
let content = std::fs::read_to_string(&path)?;
|
|
16
|
-
Ok(serde_json::from_str(&content)?)
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
// Error message: "No such file or directory (os error 2)"
|
|
20
|
-
// Which file? What were we doing?
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
## Good
|
|
24
|
-
|
|
25
|
-
```rust
|
|
26
|
-
use anyhow::{Context, Result};
|
|
27
|
-
|
|
28
|
-
fn load_user(id: u64) -> Result<User> {
|
|
29
|
-
let path = format!("users/{}.json", id);
|
|
30
|
-
|
|
31
|
-
let content = std::fs::read_to_string(&path)
|
|
32
|
-
.with_context(|| format!("failed to read user file: {}", path))?;
|
|
33
|
-
|
|
34
|
-
let user: User = serde_json::from_str(&content)
|
|
35
|
-
.with_context(|| format!("failed to parse user {} JSON", id))?;
|
|
36
|
-
|
|
37
|
-
Ok(user)
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// Error: "failed to parse user 42 JSON"
|
|
41
|
-
// Caused by: "expected ':' at line 5 column 12"
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
## context() vs with_context()
|
|
45
|
-
|
|
46
|
-
```rust
|
|
47
|
-
// context() - static string (slight allocation)
|
|
48
|
-
fs::read_to_string(path)
|
|
49
|
-
.context("failed to read config")?;
|
|
50
|
-
|
|
51
|
-
// with_context() - lazy evaluation (only allocates on error)
|
|
52
|
-
fs::read_to_string(path)
|
|
53
|
-
.with_context(|| format!("failed to read {}", path))?;
|
|
54
|
-
|
|
55
|
-
// Use with_context() when:
|
|
56
|
-
// - Message includes runtime data (format!)
|
|
57
|
-
// - Computing the message is expensive
|
|
58
|
-
// - Error path is cold (most of the time)
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
## Building Context Chains
|
|
62
|
-
|
|
63
|
-
```rust
|
|
64
|
-
fn process_order(order_id: u64) -> Result<()> {
|
|
65
|
-
let order = fetch_order(order_id)
|
|
66
|
-
.with_context(|| format!("failed to fetch order {}", order_id))?;
|
|
67
|
-
|
|
68
|
-
let user = load_user(order.user_id)
|
|
69
|
-
.with_context(|| format!("failed to load user for order {}", order_id))?;
|
|
70
|
-
|
|
71
|
-
let payment = process_payment(&order, &user)
|
|
72
|
-
.context("payment processing failed")?;
|
|
73
|
-
|
|
74
|
-
ship_order(&order, &payment)
|
|
75
|
-
.context("shipping failed")?;
|
|
76
|
-
|
|
77
|
-
Ok(())
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// Full error chain:
|
|
81
|
-
// "shipping failed"
|
|
82
|
-
// Caused by: "carrier API returned 503"
|
|
83
|
-
// Caused by: "connection refused"
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
## Displaying Error Chains
|
|
87
|
-
|
|
88
|
-
```rust
|
|
89
|
-
fn main() {
|
|
90
|
-
if let Err(e) = run() {
|
|
91
|
-
// Just top-level message
|
|
92
|
-
eprintln!("Error: {}", e);
|
|
93
|
-
|
|
94
|
-
// Full chain with alternate format
|
|
95
|
-
eprintln!("Error: {:#}", e);
|
|
96
|
-
|
|
97
|
-
// Debug format (includes backtrace if enabled)
|
|
98
|
-
eprintln!("Error: {:?}", e);
|
|
99
|
-
|
|
100
|
-
// Iterate through chain
|
|
101
|
-
for (i, cause) in e.chain().enumerate() {
|
|
102
|
-
eprintln!(" {}: {}", i, cause);
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
## With thiserror
|
|
109
|
-
|
|
110
|
-
```rust
|
|
111
|
-
use thiserror::Error;
|
|
112
|
-
|
|
113
|
-
#[derive(Error, Debug)]
|
|
114
|
-
pub enum AppError {
|
|
115
|
-
#[error("failed to load config from {path}")]
|
|
116
|
-
ConfigLoad {
|
|
117
|
-
path: String,
|
|
118
|
-
#[source]
|
|
119
|
-
cause: std::io::Error,
|
|
120
|
-
},
|
|
121
|
-
|
|
122
|
-
#[error("failed to connect to database")]
|
|
123
|
-
Database {
|
|
124
|
-
#[source]
|
|
125
|
-
cause: sqlx::Error,
|
|
126
|
-
},
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// Usage
|
|
130
|
-
fn load_config(path: &str) -> Result<Config, AppError> {
|
|
131
|
-
let content = std::fs::read_to_string(path)
|
|
132
|
-
.map_err(|e| AppError::ConfigLoad {
|
|
133
|
-
path: path.to_string(),
|
|
134
|
-
cause: e,
|
|
135
|
-
})?;
|
|
136
|
-
// ...
|
|
137
|
-
}
|
|
138
|
-
```
|
|
139
|
-
|
|
140
|
-
## See Also
|
|
141
|
-
|
|
142
|
-
- [err-anyhow-app](err-anyhow-app.md) - Use anyhow for applications
|
|
143
|
-
- [err-source-chain](err-source-chain.md) - Use #[source] to chain errors
|
|
144
|
-
- [err-question-mark](err-question-mark.md) - Use ? for propagation
|
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
# err-custom-type
|
|
2
|
-
|
|
3
|
-
> Define custom error types for domain-specific failures
|
|
4
|
-
|
|
5
|
-
## Why It Matters
|
|
6
|
-
|
|
7
|
-
Generic errors like `String`, `Box<dyn Error>`, or catch-all enums obscure what can actually go wrong. Custom error types document failure modes in the type system, enable pattern matching for specific handling, and provide clear API contracts. They make your code self-documenting and help callers handle errors appropriately.
|
|
8
|
-
|
|
9
|
-
## Bad
|
|
10
|
-
|
|
11
|
-
```rust
|
|
12
|
-
// Generic string errors - no structure
|
|
13
|
-
fn validate_user(user: &User) -> Result<(), String> {
|
|
14
|
-
if user.name.is_empty() {
|
|
15
|
-
return Err("Name is empty".to_string());
|
|
16
|
-
}
|
|
17
|
-
if user.age > 150 {
|
|
18
|
-
return Err("Age is invalid".to_string());
|
|
19
|
-
}
|
|
20
|
-
Ok(())
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
// Caller can't match on specific errors
|
|
24
|
-
match validate_user(&user) {
|
|
25
|
-
Ok(()) => save(user),
|
|
26
|
-
Err(msg) => {
|
|
27
|
-
// Can only do string comparison - fragile!
|
|
28
|
-
if msg.contains("Name") {
|
|
29
|
-
prompt_for_name()
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
## Good
|
|
36
|
-
|
|
37
|
-
```rust
|
|
38
|
-
use thiserror::Error;
|
|
39
|
-
|
|
40
|
-
#[derive(Error, Debug)]
|
|
41
|
-
pub enum ValidationError {
|
|
42
|
-
#[error("name cannot be empty")]
|
|
43
|
-
EmptyName,
|
|
44
|
-
|
|
45
|
-
#[error("name exceeds maximum length of {max} characters")]
|
|
46
|
-
NameTooLong { max: usize, actual: usize },
|
|
47
|
-
|
|
48
|
-
#[error("invalid age {0}: must be between 0 and 150")]
|
|
49
|
-
InvalidAge(u8),
|
|
50
|
-
|
|
51
|
-
#[error("email format is invalid: {0}")]
|
|
52
|
-
InvalidEmail(String),
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
fn validate_user(user: &User) -> Result<(), ValidationError> {
|
|
56
|
-
if user.name.is_empty() {
|
|
57
|
-
return Err(ValidationError::EmptyName);
|
|
58
|
-
}
|
|
59
|
-
if user.name.len() > 100 {
|
|
60
|
-
return Err(ValidationError::NameTooLong {
|
|
61
|
-
max: 100,
|
|
62
|
-
actual: user.name.len()
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
|
-
if user.age > 150 {
|
|
66
|
-
return Err(ValidationError::InvalidAge(user.age));
|
|
67
|
-
}
|
|
68
|
-
Ok(())
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// Caller can match specifically
|
|
72
|
-
match validate_user(&user) {
|
|
73
|
-
Ok(()) => save(user),
|
|
74
|
-
Err(ValidationError::EmptyName) => prompt_for_name(),
|
|
75
|
-
Err(ValidationError::InvalidAge(age)) => {
|
|
76
|
-
show_error(&format!("Please enter a valid age (you entered {})", age))
|
|
77
|
-
}
|
|
78
|
-
Err(e) => show_error(&e.to_string()),
|
|
79
|
-
}
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
## Error Type Design Guidelines
|
|
83
|
-
|
|
84
|
-
```rust
|
|
85
|
-
// 1. Group related errors in domain-specific enums
|
|
86
|
-
#[derive(Error, Debug)]
|
|
87
|
-
pub enum AuthError {
|
|
88
|
-
#[error("invalid credentials")]
|
|
89
|
-
InvalidCredentials,
|
|
90
|
-
#[error("account locked after {attempts} failed attempts")]
|
|
91
|
-
AccountLocked { attempts: u32 },
|
|
92
|
-
#[error("token expired")]
|
|
93
|
-
TokenExpired,
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
#[derive(Error, Debug)]
|
|
97
|
-
pub enum PaymentError {
|
|
98
|
-
#[error("insufficient funds: need {required}, have {available}")]
|
|
99
|
-
InsufficientFunds { required: Decimal, available: Decimal },
|
|
100
|
-
#[error("card declined: {reason}")]
|
|
101
|
-
CardDeclined { reason: String },
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// 2. Include relevant data for error handling/display
|
|
105
|
-
#[derive(Error, Debug)]
|
|
106
|
-
pub enum FileError {
|
|
107
|
-
#[error("file not found: {path}")]
|
|
108
|
-
NotFound { path: PathBuf },
|
|
109
|
-
#[error("permission denied for {path}")]
|
|
110
|
-
PermissionDenied { path: PathBuf },
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
// 3. Consider #[non_exhaustive] for public APIs
|
|
114
|
-
#[derive(Error, Debug)]
|
|
115
|
-
#[non_exhaustive] // Allows adding variants without breaking changes
|
|
116
|
-
pub enum ApiError {
|
|
117
|
-
#[error("rate limited")]
|
|
118
|
-
RateLimited,
|
|
119
|
-
#[error("not found")]
|
|
120
|
-
NotFound,
|
|
121
|
-
}
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
## When to Use What
|
|
125
|
-
|
|
126
|
-
| Error Pattern | Use Case |
|
|
127
|
-
|---------------|----------|
|
|
128
|
-
| Custom enum | Library with specific failure modes |
|
|
129
|
-
| `thiserror` | Libraries needing `std::error::Error` |
|
|
130
|
-
| `anyhow::Error` | Applications, prototypes |
|
|
131
|
-
| Struct with source | Single error type with wrapped cause |
|
|
132
|
-
|
|
133
|
-
## Struct-Based Errors
|
|
134
|
-
|
|
135
|
-
For single error types with rich context:
|
|
136
|
-
|
|
137
|
-
```rust
|
|
138
|
-
#[derive(Error, Debug)]
|
|
139
|
-
#[error("query failed for table '{table}' with filter '{filter}'")]
|
|
140
|
-
pub struct QueryError {
|
|
141
|
-
pub table: String,
|
|
142
|
-
pub filter: String,
|
|
143
|
-
#[source]
|
|
144
|
-
pub source: DatabaseError,
|
|
145
|
-
}
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
## See Also
|
|
149
|
-
|
|
150
|
-
- [err-thiserror-lib](./err-thiserror-lib.md) - thiserror for error definitions
|
|
151
|
-
- [err-anyhow-app](./err-anyhow-app.md) - When to use anyhow instead
|
|
152
|
-
- [api-non-exhaustive](./api-non-exhaustive.md) - Forward-compatible enums
|
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
# err-doc-errors
|
|
2
|
-
|
|
3
|
-
> Document error conditions with `# Errors` section in doc comments
|
|
4
|
-
|
|
5
|
-
## Why It Matters
|
|
6
|
-
|
|
7
|
-
Users of your API need to know what can go wrong and why. The `# Errors` documentation section is the standard Rust convention for describing when a function returns `Err`. Good error documentation helps callers handle errors appropriately and understand the contract of your API.
|
|
8
|
-
|
|
9
|
-
## Bad
|
|
10
|
-
|
|
11
|
-
```rust
|
|
12
|
-
/// Loads a configuration from the specified path.
|
|
13
|
-
pub fn load_config(path: &Path) -> Result<Config, ConfigError> {
|
|
14
|
-
// No documentation of error conditions
|
|
15
|
-
// Caller must read source code to understand what can fail
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/// Parses and validates the input string.
|
|
19
|
-
///
|
|
20
|
-
/// Returns the parsed value. // What about errors?
|
|
21
|
-
pub fn parse_input(input: &str) -> Result<Value, ParseError> {
|
|
22
|
-
// ...
|
|
23
|
-
}
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
## Good
|
|
27
|
-
|
|
28
|
-
```rust
|
|
29
|
-
/// Loads a configuration from the specified path.
|
|
30
|
-
///
|
|
31
|
-
/// # Errors
|
|
32
|
-
///
|
|
33
|
-
/// Returns an error if:
|
|
34
|
-
/// - The file at `path` does not exist or cannot be read
|
|
35
|
-
/// - The file contents are not valid TOML
|
|
36
|
-
/// - Required configuration keys are missing
|
|
37
|
-
/// - Configuration values are out of valid ranges
|
|
38
|
-
///
|
|
39
|
-
/// # Examples
|
|
40
|
-
///
|
|
41
|
-
/// ```
|
|
42
|
-
/// # use mylib::{load_config, ConfigError};
|
|
43
|
-
/// # fn main() -> Result<(), ConfigError> {
|
|
44
|
-
/// let config = load_config("app.toml")?;
|
|
45
|
-
/// # Ok(())
|
|
46
|
-
/// # }
|
|
47
|
-
/// ```
|
|
48
|
-
pub fn load_config(path: &Path) -> Result<Config, ConfigError> {
|
|
49
|
-
// ...
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/// Parses and validates the input string as a positive integer.
|
|
53
|
-
///
|
|
54
|
-
/// # Errors
|
|
55
|
-
///
|
|
56
|
-
/// Returns [`ParseError::Empty`] if the input is empty.
|
|
57
|
-
/// Returns [`ParseError::InvalidFormat`] if the input contains non-digit characters.
|
|
58
|
-
/// Returns [`ParseError::Overflow`] if the value exceeds `i64::MAX`.
|
|
59
|
-
/// Returns [`ParseError::NotPositive`] if the value is zero or negative.
|
|
60
|
-
pub fn parse_positive_int(input: &str) -> Result<i64, ParseError> {
|
|
61
|
-
// ...
|
|
62
|
-
}
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
## Linking to Error Variants
|
|
66
|
-
|
|
67
|
-
```rust
|
|
68
|
-
/// Attempts to connect to the database.
|
|
69
|
-
///
|
|
70
|
-
/// # Errors
|
|
71
|
-
///
|
|
72
|
-
/// This function will return an error if:
|
|
73
|
-
///
|
|
74
|
-
/// - [`DbError::ConnectionFailed`] - The database server is unreachable
|
|
75
|
-
/// - [`DbError::AuthenticationFailed`] - Invalid credentials
|
|
76
|
-
/// - [`DbError::Timeout`] - Connection attempt exceeded timeout
|
|
77
|
-
/// - [`DbError::TlsError`] - TLS handshake failed
|
|
78
|
-
///
|
|
79
|
-
/// See [`DbError`] for more details on each variant.
|
|
80
|
-
pub fn connect(config: &DbConfig) -> Result<Connection, DbError> {
|
|
81
|
-
// ...
|
|
82
|
-
}
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
## Panic vs Error Documentation
|
|
86
|
-
|
|
87
|
-
```rust
|
|
88
|
-
/// Divides two numbers.
|
|
89
|
-
///
|
|
90
|
-
/// # Errors
|
|
91
|
-
///
|
|
92
|
-
/// Returns [`MathError::DivisionByZero`] if `divisor` is zero.
|
|
93
|
-
///
|
|
94
|
-
/// # Panics
|
|
95
|
-
///
|
|
96
|
-
/// Panics if called from a non-main thread (debug builds only).
|
|
97
|
-
pub fn divide(dividend: i64, divisor: i64) -> Result<i64, MathError> {
|
|
98
|
-
// ...
|
|
99
|
-
}
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
## Error Section Format Options
|
|
103
|
-
|
|
104
|
-
```rust
|
|
105
|
-
// Style 1: Bullet list (good for multiple conditions)
|
|
106
|
-
/// # Errors
|
|
107
|
-
///
|
|
108
|
-
/// Returns an error if:
|
|
109
|
-
/// - The file does not exist
|
|
110
|
-
/// - The file cannot be read
|
|
111
|
-
/// - The content is invalid UTF-8
|
|
112
|
-
|
|
113
|
-
// Style 2: Returns statements (good for mapping to variants)
|
|
114
|
-
/// # Errors
|
|
115
|
-
///
|
|
116
|
-
/// Returns [`Error::NotFound`] if the item doesn't exist.
|
|
117
|
-
/// Returns [`Error::PermissionDenied`] if access is forbidden.
|
|
118
|
-
|
|
119
|
-
// Style 3: Prose (good for complex conditions)
|
|
120
|
-
/// # Errors
|
|
121
|
-
///
|
|
122
|
-
/// This function returns an error when the input fails validation.
|
|
123
|
-
/// Validation includes checking that all required fields are present,
|
|
124
|
-
/// that numeric fields are within allowed ranges, and that string
|
|
125
|
-
/// fields match their expected formats.
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
## Clippy Lint
|
|
129
|
-
|
|
130
|
-
```toml
|
|
131
|
-
# Cargo.toml - require error documentation
|
|
132
|
-
[lints.clippy]
|
|
133
|
-
missing_errors_doc = "warn"
|
|
134
|
-
```
|
|
135
|
-
|
|
136
|
-
```rust
|
|
137
|
-
// This will warn without # Errors section
|
|
138
|
-
pub fn might_fail() -> Result<(), Error> { Ok(()) }
|
|
139
|
-
```
|
|
140
|
-
|
|
141
|
-
## See Also
|
|
142
|
-
|
|
143
|
-
- [doc-examples-section](./doc-examples-section.md) - Examples in documentation
|
|
144
|
-
- [err-thiserror-lib](./err-thiserror-lib.md) - Defining error types
|
|
145
|
-
- [api-must-use](./api-must-use.md) - Marking Results as must_use
|