mirror of
https://github.com/eyre-rs/eyre.git
synced 2025-09-27 04:50:50 +00:00
Merge remote-tracking branch 'origin/master' into color-eyre
This commit is contained in:
commit
57216d0b14
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,3 +1,4 @@
|
||||
/target
|
||||
**/*.rs.bk
|
||||
Cargo.lock
|
||||
tags
|
||||
|
181
CONTRIBUTING.md
Normal file
181
CONTRIBUTING.md
Normal file
@ -0,0 +1,181 @@
|
||||
# Welcome to the eyre contributing guide
|
||||
|
||||
Thank you for investing your time in contributing to our project! Eyre is a
|
||||
community owned and maintained project dedicated to improving the error
|
||||
handling and error reporting experience of users of the Rust programming
|
||||
language.
|
||||
|
||||
Check out our community's[^1] [Code of
|
||||
Conduct](https://www.rust-lang.org/policies/code-of-conduct) and feel free to
|
||||
say hi on [Discord] if you'd like. It's a nice place to chat about eyre
|
||||
development, ask questions, and get to know the other contributors and users in
|
||||
a less formal setting.
|
||||
|
||||
## The Eyre Organization
|
||||
|
||||
The Eyre Organization is the group of people responsible for stewarding the
|
||||
Eyre project. It handles things like merging pull requests, choosing project
|
||||
direction, managing bugs / issues / feature requests, controlling access to
|
||||
secrets, defining and enforcing best practices, etc.
|
||||
|
||||
The eyre organization's governance is based on and inspired by
|
||||
[sociocracy](https://www.sociocracyforall.org/sociocracy/), the Rust Project,
|
||||
and the Bevy Organization. Many thanks to their great examples and resources.
|
||||
|
||||
Note that you *do not* need to be a member of the Eyre Organization to
|
||||
contribute to Eyre. Community contributors (this means you) can freely open
|
||||
issues, submit pull requests, and review pull requests.
|
||||
|
||||
### New contributor guide
|
||||
|
||||
To get an overview of the project, read the [README](README.md). Here are some
|
||||
resources to help you get started with open source contributions:
|
||||
|
||||
- [Finding ways to contribute to open source on GitHub](https://docs.github.com/en/get-started/exploring-projects-on-github/finding-ways-to-contribute-to-open-source-on-github)
|
||||
- [Set up Git](https://docs.github.com/en/get-started/quickstart/set-up-git)
|
||||
- [GitHub flow](https://docs.github.com/en/get-started/quickstart/github-flow)
|
||||
- [Collaborating with pull requests](https://docs.github.com/en/github/collaborating-with-pull-requests)
|
||||
|
||||
Your first PR will be merged in no time!
|
||||
|
||||
No matter how you're helping: thank you for contributing to Eyre!
|
||||
|
||||
### Classifying PRs
|
||||
|
||||
We use labels to organize our issues and PRs.
|
||||
|
||||
Each [label](https://github.com/eyre-rs/eyre/labels) has a prefix denoting its category:
|
||||
|
||||
* A: Area or subcrate (e.g. A-eyre, A-color-eyre, A-color-spantrace)
|
||||
* C: Category (e.g. C-Breaking-Change, C-Code-Quality, C-Docs)
|
||||
* P: Priority (e.g. P-Urgent, P-Important)
|
||||
* S: Status (e.g. S-Blocked, S-Controversial, S-Needs-Design)
|
||||
* Misc (e.g. "good first issue", "help wanted", "duplicate", "invalid", "wontfix")
|
||||
|
||||
## Making changes to Eyre
|
||||
|
||||
Most changes don't require much process. If your change is relatively straightforward, just do the following:
|
||||
|
||||
1. A community member (that's you!) creates one of the following:
|
||||
* [GitHub Discussions]: An informal discussion with the community. This is
|
||||
the place to start if you want to propose a feature or specific
|
||||
implementation and gathering community wisdom and advice before jumping
|
||||
to solutions.
|
||||
* [Issue](https://github.com/eyre-rs/eyre/issues): A formal way for us to
|
||||
track a bug or feature. Please look for duplicates before opening a new
|
||||
issue and consider starting with a Discussion.
|
||||
* [Pull Request](https://github.com/eyre-rs/eyre/pulls) (or PR for short):
|
||||
A request to merge code changes. This starts our "review process". You
|
||||
are welcome to start with a pull request, but consider starting with an
|
||||
Issue or Discussion for larger changes (or if you aren't certain about a
|
||||
design). We don't want anyone to waste their time on code that didn't
|
||||
have a chance to be merged! But conversely, sometimes PRs are the most
|
||||
efficient way to propose a change. Just use your own judgement here.
|
||||
2. Other community members review and comment in an ad-hoc fashion. Active
|
||||
subject matter experts may be pulled into a thread using `@mentions`. If
|
||||
your PR has been quiet for a while and is ready for review, feel free to
|
||||
leave a message to "bump" the thread, or bring it up on [Discord]
|
||||
3. Once they're content with the pull request (design, code quality,
|
||||
documentation, tests), individual reviewers leave "Approved" reviews.
|
||||
4. After consensus has been reached (typically two approvals from the community
|
||||
or one for extremely simple changes) and CI passes, the
|
||||
[S-Ready-For-Final-Review](https://github.com/eyre-rs/eyre/issues?q=is%3Aopen+is%3Aissue+label%3AS-Ready-For-Final-Review)
|
||||
label is added.
|
||||
5. When they find time, someone with merge rights performs a final code review
|
||||
and queue the PR for merging.
|
||||
|
||||
## How you can help
|
||||
|
||||
If you've made it to this page, you're probably already convinced that Eyre is
|
||||
a project you'd like to see thrive. But how can *you* help?
|
||||
|
||||
No matter your experience level with Eyre or Rust or your level of commitment,
|
||||
there are ways to meaningfully contribute. Take a look at the sections that
|
||||
follow to pick a route (or five) that appeal to you.
|
||||
|
||||
If you ever find yourself at a loss for what to do, or in need of mentorship or
|
||||
advice on how to contribute to Eyre, feel free to ask in [Discord] and one of
|
||||
our more experienced community members will be happy to help.
|
||||
|
||||
### Writing Handlers
|
||||
|
||||
You can improve Eyre's ecosystem by building your own
|
||||
[EyreHandler](https://docs.rs/eyre/0.6.8/eyre/trait.EyreHandler.html) crates
|
||||
like [color-eyre](https://github.com/eyre-rs/color-eyre/). The customizable
|
||||
reporting of `eyre` is it's secret sauce, using that customizability in
|
||||
creative ways and sharing your work is one of the best ways you can inspire
|
||||
others and help grow our community.
|
||||
|
||||
### Fixing bugs
|
||||
|
||||
Bugs in Eyre are filed on the issue tracker using the [`C-bug`](https://github.com/eyre-rs/eyre/issues?q=is%3Aissue+is%3Aopen+label%3AC-Bug) label.
|
||||
|
||||
If you're looking for an easy place to start, take a look at the [`good first
|
||||
issue`](https://github.com/eyre-rs/eyre/labels/good%20first%20issue) label, and
|
||||
feel free to ask questions on that issue's thread in question or on [Discord].
|
||||
You don't need anyone's permission to try fixing a bug or adding a simple
|
||||
feature, but stating that you'd like to tackle an issue can be helpful to avoid
|
||||
duplicated work.
|
||||
|
||||
When you make a pull request that fixes an issue, include a line that says
|
||||
`Fixes #X` (or "Closes"), where `X` is the issue number. This will cause the
|
||||
issue in question to be closed when your PR is merged.
|
||||
|
||||
General improvements to code quality are also welcome!
|
||||
Eyre can always be safer, better tested, and more idiomatic.
|
||||
|
||||
### Writing docs
|
||||
|
||||
This is incredibly valuable, easily distributed work, but requires a bit of guidance:
|
||||
|
||||
* Inaccurate documentation is worse than no documentation: prioritize fixing
|
||||
broken docs.
|
||||
* Code documentation (doc examples and in the examples folder) is easier to
|
||||
maintain because the compiler will tell us when it breaks.
|
||||
* Inline documentation should be technical and to the point. Link relevant
|
||||
examples or other explanations if broader context is useful.
|
||||
|
||||
### Reviewing others' work
|
||||
|
||||
Reviewing others work with the aim of improving it is one of the most helpful
|
||||
things you can do. You don't need to be an Elder Rustacean to be useful here:
|
||||
anyone can catch missing tests, unclear docs, logic errors, and so on. If you
|
||||
have specific skills (e.g. advanced familiarity with `unsafe` code, rendering
|
||||
knowledge or web development experience) or personal experience with a problem,
|
||||
try to prioritize those areas to ensure we can get appropriate expertise where
|
||||
we need it.
|
||||
|
||||
Focus on giving constructive, actionable feedback that results in real
|
||||
improvements to code quality or end-user experience. If you don't understand
|
||||
why an approach was taken, please ask!
|
||||
|
||||
Provide actual code suggestions when that is helpful. Small changes work well
|
||||
as comments or in-line suggestions on specific lines of codes. Larger changes
|
||||
deserve a comment in the main thread, or a pull request to the original
|
||||
author's branch (but please mention that you've made one).
|
||||
|
||||
Once you're happy with the work and feel you're reasonably qualified to assess
|
||||
quality in this particular area, leave your `Approved` review on the PR. If
|
||||
you're new to GitHub, check out the [Pull Request Review
|
||||
documentation](https://docs.github.com/en/github/collaborating-with-pull-requests/reviewing-changes-in-pull-requests/about-pull-request-reviews).
|
||||
Anyone can leave reviews ... no special permissions are required!
|
||||
|
||||
There are three main places you can check for things to review:
|
||||
|
||||
1. Pull request which are ready and in need of more reviews on
|
||||
[eyre](https://github.com/eyre-rs/eyre/pulls?q=is%3Aopen+is%3Apr+-label%3AS-Ready-For-Final-Review+-draft%3A%3Atrue+-label%3AS-Needs-RFC+-reviewed-by%3A%40me+-author%3A%40me)
|
||||
2. Pull requests on [eyre](https://github.com/eyre-rs/eyre/pulls) and the
|
||||
[color-eyre](https://github.com/eyre-rs/color-eyre/pulls) repos.
|
||||
|
||||
Not even our Circle Members are exempt from reviews! By giving feedback on this
|
||||
work (and related supporting work), you can help us make sure our releases are
|
||||
both high-quality and timely.
|
||||
|
||||
Finally, if nothing brings you more satisfaction than seeing every last issue
|
||||
labeled and all resolved issues closed, feel free to message any Eyre Circle
|
||||
Member (currently @yaahc) for the triage role to help us keep things tidy. This
|
||||
role only requires good faith and a basic understanding of our development
|
||||
process.
|
||||
|
||||
[Discord]: https://discord.gg/z94RqmUTKB
|
||||
[^1]: Okay, I'll admit it, it's really just the Rust Project's CoC :sweat_smile:
|
36
README.md
36
README.md
@ -174,23 +174,9 @@ avoid using `eyre::Report` as your public error type.
|
||||
|
||||
## No-std support
|
||||
|
||||
**NOTE**: tests are currently broken for `no_std` so I cannot guarantee that
|
||||
everything works still. I'm waiting for upstream fixes to be merged rather than
|
||||
fixing them myself, so bear with me.
|
||||
|
||||
In no_std mode, the same API is almost all available and works the same way. To
|
||||
depend on Eyre in no_std mode, disable our default enabled "std" feature in
|
||||
Cargo.toml. A global allocator is required.
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
eyre = { version = "0.6", default-features = false }
|
||||
```
|
||||
|
||||
Since the `?`-based error conversions would normally rely on the
|
||||
`std::error::Error` trait which is only available through std, no_std mode will
|
||||
require an explicit `.map_err(Report::msg)` when working with a non-Eyre error
|
||||
type inside a function that returns Eyre's error type.
|
||||
No-std support was removed in 2020 in [commit 608a16a] due to unaddressed upstream breakages.
|
||||
[commit 608a16a]:
|
||||
https://github.com/eyre-rs/eyre/pull/29/commits/608a16aa2c2c27eca6c88001cc94c6973c18f1d5
|
||||
|
||||
## Comparison to failure
|
||||
|
||||
@ -225,24 +211,30 @@ implies that you're creating a new error that saves the old error as its
|
||||
`source`. With `Option` there is no source error to wrap, so `wrap_err` ends up
|
||||
being somewhat meaningless.
|
||||
|
||||
Instead `eyre` intends for users to use the combinator functions provided by
|
||||
`std` for converting `Option`s to `Result`s. So where you would write this with
|
||||
Instead `eyre` offers [`OptionExt::ok_or_eyre`] to yield _static_ errors from `None`,
|
||||
and intends for users to use the combinator functions provided by
|
||||
`std`, converting `Option`s to `Result`s, for _dynamic_ errors.
|
||||
So where you would write this with
|
||||
anyhow:
|
||||
|
||||
[`OptionExt::ok_or_eyre`]: https://docs.rs/eyre/latest/eyre/trait.OptionExt.html#tymethod.ok_or_eyre
|
||||
|
||||
```rust
|
||||
use anyhow::Context;
|
||||
|
||||
let opt: Option<()> = None;
|
||||
let result = opt.context("new error message");
|
||||
let result_static = opt.context("static error message");
|
||||
let result_dynamic = opt.with_context(|| format!("{} error message", "dynamic"));
|
||||
```
|
||||
|
||||
With `eyre` we want users to write:
|
||||
|
||||
```rust
|
||||
use eyre::{eyre, Result};
|
||||
use eyre::{eyre, OptionExt, Result};
|
||||
|
||||
let opt: Option<()> = None;
|
||||
let result: Result<()> = opt.ok_or_else(|| eyre!("new error message"));
|
||||
let result_static: Result<()> = opt.ok_or_eyre("static error message");
|
||||
let result_dynamic: Result<()> = opt.ok_or_else(|| eyre!("{} error message", "dynamic"));
|
||||
```
|
||||
|
||||
**NOTE**: However, to help with porting we do provide a `ContextCompat` trait which
|
||||
|
@ -8,6 +8,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## [Unreleased] - ReleaseDate
|
||||
|
||||
## [0.2.1] - 2023-11-17
|
||||
### Fixed
|
||||
- Add license files [by erickt](https://github.com/eyre-rs/color-spantrace/pull/19)
|
||||
|
||||
## [0.2.0] - 2022-01-12
|
||||
### Changed
|
||||
- Updated dependency versions to match latest tracing versions
|
||||
@ -22,7 +26,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- Support custom color themes for spantrace format
|
||||
|
||||
<!-- next-url -->
|
||||
[Unreleased]: https://github.com/eyre-rs/color-spantrace/compare/v0.2.0...HEAD
|
||||
[Unreleased]: https://github.com/eyre-rs/color-spantrace/compare/v0.2.1...HEAD
|
||||
[0.2.1]: https://github.com/eyre-rs/color-spantrace/compare/v0.2.0...v0.2.1
|
||||
[0.2.0]: https://github.com/eyre-rs/color-spantrace/compare/v0.1.6...v0.2.0
|
||||
[0.1.6]: https://github.com/eyre-rs/color-spantrace/compare/v0.1.5...v0.1.6
|
||||
[v0.1.5]: https://github.com/eyre-rs/color-spantrace/releases/tag/v0.1.5
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "color-spantrace"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
description = "A pretty printer for tracing_error::SpanTrace based on color-backtrace"
|
||||
documentation = "https://docs.rs/color-spantrace"
|
||||
|
||||
@ -26,43 +26,5 @@ ansi-parser = "0.8" # used for testing color schemes
|
||||
all-features = true
|
||||
rustdoc-args = ["--cfg", "docsrs"]
|
||||
|
||||
[package.metadata.release]
|
||||
dev-version = false
|
||||
|
||||
[[package.metadata.release.pre-release-replacements]]
|
||||
file = "CHANGELOG.md"
|
||||
search = "Unreleased"
|
||||
replace="{{version}}"
|
||||
|
||||
[[package.metadata.release.pre-release-replacements]]
|
||||
file = "src/lib.rs"
|
||||
search = "#!\\[doc\\(html_root_url.*"
|
||||
replace = "#![doc(html_root_url = \"https://docs.rs/{{crate_name}}/{{version}}\")]"
|
||||
exactly = 1
|
||||
|
||||
[[package.metadata.release.pre-release-replacements]]
|
||||
file = "CHANGELOG.md"
|
||||
search = "\\.\\.\\.HEAD"
|
||||
replace="...{{tag_name}}"
|
||||
exactly = 1
|
||||
|
||||
[[package.metadata.release.pre-release-replacements]]
|
||||
file = "CHANGELOG.md"
|
||||
search = "ReleaseDate"
|
||||
replace="{{date}}"
|
||||
|
||||
[[package.metadata.release.pre-release-replacements]]
|
||||
file="CHANGELOG.md"
|
||||
search="<!-- next-header -->"
|
||||
replace="<!-- next-header -->\n\n## [Unreleased] - ReleaseDate"
|
||||
exactly=1
|
||||
|
||||
[[package.metadata.release.pre-release-replacements]]
|
||||
file="CHANGELOG.md"
|
||||
search="<!-- next-url -->"
|
||||
replace="<!-- next-url -->\n[Unreleased]: https://github.com/eyre-rs/{{crate_name}}/compare/{{tag_name}}...HEAD"
|
||||
exactly=1
|
||||
|
||||
[[example]]
|
||||
name = "color-spantrace-usage"
|
||||
path = "examples/usage.rs"
|
||||
[package.metadata.workspaces]
|
||||
independent = true
|
||||
|
@ -58,7 +58,7 @@ println!("{}", color_spantrace::colorize(&span_trace));
|
||||
|
||||
## Example
|
||||
|
||||
This example is taken from `examples/usage.rs`:
|
||||
This example is taken from `examples/color-spantrace-usage.rs`:
|
||||
|
||||
```rust
|
||||
use tracing::instrument;
|
||||
|
53
color-spantrace/build.rs
Normal file
53
color-spantrace/build.rs
Normal file
@ -0,0 +1,53 @@
|
||||
use std::env;
|
||||
use std::ffi::OsString;
|
||||
use std::process::Command;
|
||||
use std::str;
|
||||
|
||||
fn main() {
|
||||
let version = match rustc_version_info() {
|
||||
Some(version) => version,
|
||||
None => return,
|
||||
};
|
||||
version.toolchain.set_feature();
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
enum Toolchain {
|
||||
Stable,
|
||||
Beta,
|
||||
Nightly,
|
||||
}
|
||||
|
||||
impl Toolchain {
|
||||
fn set_feature(self) {
|
||||
match self {
|
||||
Toolchain::Nightly => println!("cargo:rustc-cfg=nightly"),
|
||||
Toolchain::Beta => println!("cargo:rustc-cfg=beta"),
|
||||
Toolchain::Stable => println!("cargo:rustc-cfg=stable"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct VersionInfo {
|
||||
toolchain: Toolchain,
|
||||
}
|
||||
|
||||
fn rustc_version_info() -> Option<VersionInfo> {
|
||||
let rustc = env::var_os("RUSTC").unwrap_or_else(|| OsString::from("rustc"));
|
||||
let output = Command::new(rustc).arg("--version").output().ok()?;
|
||||
let version = str::from_utf8(&output.stdout).ok()?;
|
||||
let mut pieces = version.split(['.', ' ', '-']);
|
||||
if pieces.next() != Some("rustc") {
|
||||
return None;
|
||||
}
|
||||
let _major: u32 = pieces.next()?.parse().ok()?;
|
||||
let _minor: u32 = pieces.next()?.parse().ok()?;
|
||||
let _patch: u32 = pieces.next()?.parse().ok()?;
|
||||
let toolchain = match pieces.next() {
|
||||
Some("beta") => Toolchain::Beta,
|
||||
Some("nightly") => Toolchain::Nightly,
|
||||
_ => Toolchain::Stable,
|
||||
};
|
||||
let version = VersionInfo { toolchain };
|
||||
Some(version)
|
||||
}
|
@ -45,25 +45,29 @@
|
||||
//!
|
||||
//! ## Output Format
|
||||
//!
|
||||
//! Running `examples/usage.rs` from the `color-spantrace` repo produces the following output:
|
||||
//! Running `examples/color-spantrace-usage.rs` from the `color-spantrace` repo produces the following output:
|
||||
//!
|
||||
//! <pre><font color="#4E9A06"><b>❯</b></font> cargo run --example usage
|
||||
//! <pre><font color="#4E9A06"><b>❯</b></font> cargo run --example color-spantrace-usage
|
||||
//! <font color="#4E9A06"><b> Finished</b></font> dev [unoptimized + debuginfo] target(s) in 0.04s
|
||||
//! <font color="#4E9A06"><b> Running</b></font> `target/debug/examples/usage`
|
||||
//! <font color="#4E9A06"><b> Running</b></font> `target/debug/examples/color-spantrace-usage`
|
||||
//! ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ SPANTRACE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
//!
|
||||
//! 0: <font color="#F15D22">usage::two</font>
|
||||
//! at <font color="#75507B">examples/usage.rs</font>:<font color="#75507B">18</font>
|
||||
//! 1: <font color="#F15D22">usage::one</font> with <font color="#34E2E2">i=42</font>
|
||||
//! at <font color="#75507B">examples/usage.rs</font>:<font color="#75507B">13</font></pre>
|
||||
//! 0: <font color="#F15D22">color-spantrace-usage::two</font>
|
||||
//! at <font color="#75507B">examples/color-spantrace-usage.rs</font>:<font color="#75507B">18</font>
|
||||
//! 1: <font color="#F15D22">color-spantrace-usage::one</font> with <font color="#34E2E2">i=42</font>
|
||||
//! at <font color="#75507B">examples/color-spantrace-usage.rs</font>:<font color="#75507B">13</font></pre>
|
||||
//!
|
||||
//! [`tracing_error::SpanTrace`]: https://docs.rs/tracing-error/*/tracing_error/struct.SpanTrace.html
|
||||
//! [`color-backtrace`]: https://github.com/athre0z/color-backtrace
|
||||
#![doc(html_root_url = "https://docs.rs/color-spantrace/0.2.0")]
|
||||
#![doc(html_root_url = "https://docs.rs/color-spantrace/0.2.1")]
|
||||
#![cfg_attr(
|
||||
nightly,
|
||||
feature(rustdoc_missing_doc_code_examples),
|
||||
warn(rustdoc::missing_doc_code_examples)
|
||||
)]
|
||||
#
|
||||
|
||||
### Added
|
||||
- one-argument ensure!($expr) [by sharnoff](https://github.com/eyre-rs/eyre/pull/86)
|
||||
- documentation on the performance characteristics of `wrap_err` vs `wrap_err_with` [by akshayknarayan](https://github.com/eyre-rs/eyre/pull/93)
|
||||
- tl;dr: `wrap_err_with` is faster unless the constructed error object already exists
|
||||
- automated conversion to external errors for ensure! and bail! [by j-baker](https://github.com/eyre-rs/eyre/pull/95)
|
||||
- eyre::Ok for generating eyre::Ok() without fully specifying the type [by kylewlacy](https://github.com/eyre-rs/eyre/pull/91)
|
||||
- `OptionExt::ok_or_eyre` for yielding static `Report`s from `None` [by LeoniePhiline](https://github.com/eyre-rs/eyre/pull/125)
|
||||
|
||||
### New Contributors
|
||||
- @sharnoff made their first contribution in https://github.com/eyre-rs/eyre/pull/86
|
||||
- @akshayknarayan made their first contribution in https://github.com/eyre-rs/eyre/pull/93
|
||||
- @j-baker made their first contribution in https://github.com/eyre-rs/eyre/pull/95
|
||||
- @kylewlacy made their first contribution in https://github.com/eyre-rs/eyre/pull/91
|
||||
- @LeoniePhiline made their first contribution in https://github.com/eyre-rs/eyre/pull/129
|
||||
|
||||
## [0.6.9] - 2023-11-17
|
||||
### Fixed
|
||||
- stacked borrows when dropping [by TimDiekmann](https://github.com/eyre-rs/eyre/pull/81)
|
||||
- miri validation errors through now stricter provenance [by ten3roberts](https://github.com/eyre-rs/eyre/pull/103)
|
||||
- documentation on no_std support [by thenorili](https://github.com/eyre-rs/eyre/pull/111)
|
||||
|
||||
### Added
|
||||
- monorepo for eyre-related crates [by pksunkara](https://github.com/eyre-rs/eyre/pull/104), [[2]](https://github.com/eyre-rs/eyre/pull/105)[[3]](https://github.com/eyre-rs/eyre/pull/107)
|
||||
- CONTRIBUTING.md [by yaahc](https://github.com/eyre-rs/eyre/pull/99)
|
||||
|
||||
## [0.6.8] - 2022-04-04
|
||||
### Added
|
||||
- Add `#[must_use]` to `Report`
|
||||
- Add `must-install` feature to help reduce binary sizes when using a custom `EyreHandler`
|
||||
- `#[must_use]` to `Report`
|
||||
- `must-install` feature to help reduce binary sizes when using a custom `EyreHandler`
|
||||
|
||||
## [0.6.7] - 2022-02-24
|
||||
### Fixed
|
||||
- added missing track_caller annotation to new format arg capture constructor
|
||||
- missing track_caller annotation to new format arg capture constructor
|
||||
|
||||
## [0.6.6] - 2022-01-19
|
||||
### Added
|
||||
- add support for format arguments capture on 1.58 and later
|
||||
- support for format arguments capture on 1.58 and later
|
||||
|
||||
## [0.6.5] - 2021-01-05
|
||||
### Added
|
||||
- add optional support for converting into `pyo3` exceptions
|
||||
- optional support for converting into `pyo3` exceptions
|
||||
|
||||
## [0.6.4] - 2021-01-04
|
||||
### Fixed
|
||||
- added missing track_caller annotations to `wrap_err` related trait methods
|
||||
- missing track_caller annotations to `wrap_err` related trait methods
|
||||
|
||||
## [0.6.3] - 2020-11-10
|
||||
### Fixed
|
||||
- added missing track_caller annotation to autoref specialization functions
|
||||
- missing track_caller annotation to autoref specialization functions
|
||||
|
||||
## [0.6.2] - 2020-10-27
|
||||
### Fixed
|
||||
- added missing track_caller annotation to new_adhoc function
|
||||
- missing track_caller annotation to new_adhoc function
|
||||
|
||||
## [0.6.1] - 2020-09-28
|
||||
### Added
|
||||
- support track_caller on rust versions where it is available
|
||||
- support for track_caller on rust versions where it is available
|
||||
|
||||
|
||||
<!-- next-url -->
|
||||
[Unreleased]: https://github.com/eyre-rs/eyre/compare/v0.6.8...HEAD
|
||||
[0.6.8]: https://github.com/eyre-rs/eyre/compare/v0.6.7...v0.6.8
|
||||
[0.6.7]: https://github.com/eyre-rs/eyre/compare/v0.6.6...v0.6.7
|
||||
[0.6.6]: https://github.com/eyre-rs/eyre/compare/v0.6.5...v0.6.6
|
||||
[0.6.5]: https://github.com/eyre-rs/eyre/compare/v0.6.4...v0.6.5
|
||||
[0.6.4]: https://github.com/eyre-rs/eyre/compare/v0.6.3...v0.6.4
|
||||
[0.6.3]: https://github.com/eyre-rs/eyre/compare/v0.6.2...v0.6.3
|
||||
[0.6.2]: https://github.com/eyre-rs/eyre/compare/v0.6.1...v0.6.2
|
||||
[0.6.1]: https://github.com/eyre-rs/eyre/releases/tag/v0.6.1
|
||||
[Unreleased]: https://github.com/eyre-rs/eyre/compare/v0.6.10...HEAD
|
||||
[0.6.10]: https://github.com/eyre-rs/eyre/compare/v0.6.9...v0.6.10
|
||||
[0.6.9]: https://github.com/eyre-rs/eyre/compare/v0.6.8...v0.6.9
|
||||
[0.6.8]: https://github.com/eyre-rs/eyre/compare/v0.6.7...v0.6.8
|
||||
[0.6.7]: https://github.com/eyre-rs/eyre/compare/v0.6.6...v0.6.7
|
||||
[0.6.6]: https://github.com/eyre-rs/eyre/compare/v0.6.5...v0.6.6
|
||||
[0.6.5]: https://github.com/eyre-rs/eyre/compare/v0.6.4...v0.6.5
|
||||
[0.6.4]: https://github.com/eyre-rs/eyre/compare/v0.6.3...v0.6.4
|
||||
[0.6.3]: https://github.com/eyre-rs/eyre/compare/v0.6.2...v0.6.3
|
||||
[0.6.2]: https://github.com/eyre-rs/eyre/compare/v0.6.1...v0.6.2
|
||||
[0.6.1]: https://github.com/eyre-rs/eyre/releases/tag/v0.6.1
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "eyre"
|
||||
version = "0.6.8"
|
||||
version = "0.6.10"
|
||||
authors = ["David Tolnay <dtolnay@gmail.com>", "Jane Lusby <jlusby42@gmail.com>"]
|
||||
description = "Flexible concrete Error Reporting type built on std::error::Error with customizable Reports"
|
||||
documentation = "https://docs.rs/eyre"
|
||||
@ -20,7 +20,7 @@ track-caller = []
|
||||
[dependencies]
|
||||
indenter = { workspace = true }
|
||||
once_cell = { workspace = true }
|
||||
pyo3 = { version = "0.13", optional = true, default-features = false }
|
||||
pyo3 = { version = "0.20", optional = true, default-features = false }
|
||||
|
||||
[dev-dependencies]
|
||||
futures = { version = "0.3", default-features = false }
|
||||
@ -30,45 +30,12 @@ trybuild = { version = "1.0.19", features = ["diff"] }
|
||||
backtrace = "0.3.46"
|
||||
anyhow = "1.0.28"
|
||||
syn = { version = "2.0", features = ["full"] }
|
||||
pyo3 = { version = "0.13", default-features = false, features = ["auto-initialize"] }
|
||||
pyo3 = { version = "0.20", default-features = false, features = ["auto-initialize"] }
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
rustdoc-args = ["--cfg", "doc_cfg"]
|
||||
|
||||
[package.metadata.release]
|
||||
dev-version = false
|
||||
[package.metadata.workspaces]
|
||||
independent = true
|
||||
|
||||
[[package.metadata.release.pre-release-replacements]]
|
||||
file = "CHANGELOG.md"
|
||||
search = "Unreleased"
|
||||
replace = "{{version}}"
|
||||
|
||||
[[package.metadata.release.pre-release-replacements]]
|
||||
file = "src/lib.rs"
|
||||
search = "#!\\[doc\\(html_root_url.*"
|
||||
replace = "#![doc(html_root_url = \"https://docs.rs/{{crate_name}}/{{version}}\")]"
|
||||
exactly = 1
|
||||
|
||||
[[package.metadata.release.pre-release-replacements]]
|
||||
file = "CHANGELOG.md"
|
||||
search = "\\.\\.\\.HEAD"
|
||||
replace = "...{{tag_name}}"
|
||||
exactly = 1
|
||||
|
||||
[[package.metadata.release.pre-release-replacements]]
|
||||
file = "CHANGELOG.md"
|
||||
search = "ReleaseDate"
|
||||
replace = "{{date}}"
|
||||
|
||||
[[package.metadata.release.pre-release-replacements]]
|
||||
file = "CHANGELOG.md"
|
||||
search = "<!-- next-header -->"
|
||||
replace = "<!-- next-header -->\n\n## [Unreleased] - ReleaseDate"
|
||||
exactly = 1
|
||||
|
||||
[[package.metadata.release.pre-release-replacements]]
|
||||
file = "CHANGELOG.md"
|
||||
search = "<!-- next-url -->"
|
||||
replace = "<!-- next-url -->\n[Unreleased]: https://github.com/eyre-rs/{{crate_name}}/compare/{{tag_name}}...HEAD"
|
||||
exactly = 1
|
||||
|
@ -1,4 +1,5 @@
|
||||
use std::env;
|
||||
use std::ffi::OsString;
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
use std::process::{Command, ExitStatus};
|
||||
@ -55,16 +56,18 @@ fn main() {
|
||||
_ => {}
|
||||
}
|
||||
|
||||
let rustc = match rustc_minor_version() {
|
||||
Some(rustc) => rustc,
|
||||
let version = match rustc_version_info() {
|
||||
Some(version) => version,
|
||||
None => return,
|
||||
};
|
||||
|
||||
if rustc < 52 {
|
||||
version.toolchain.set_feature();
|
||||
|
||||
if version.minor < 52 {
|
||||
println!("cargo:rustc-cfg=eyre_no_fmt_arguments_as_str");
|
||||
}
|
||||
|
||||
if rustc < 58 {
|
||||
if version.minor < 58 {
|
||||
println!("cargo:rustc-cfg=eyre_no_fmt_args_capture");
|
||||
}
|
||||
}
|
||||
@ -86,13 +89,44 @@ fn compile_probe(probe: &str) -> Option<ExitStatus> {
|
||||
.ok()
|
||||
}
|
||||
|
||||
fn rustc_minor_version() -> Option<u32> {
|
||||
let rustc = env::var_os("RUSTC")?;
|
||||
// TODO factor this toolchain parsing and related tests into its own file
|
||||
#[derive(PartialEq)]
|
||||
enum Toolchain {
|
||||
Stable,
|
||||
Beta,
|
||||
Nightly,
|
||||
}
|
||||
impl Toolchain {
|
||||
fn set_feature(self) {
|
||||
match self {
|
||||
Toolchain::Nightly => println!("cargo:rustc-cfg=nightly"),
|
||||
Toolchain::Beta => println!("cargo:rustc-cfg=beta"),
|
||||
Toolchain::Stable => println!("cargo:rustc-cfg=stable"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct VersionInfo {
|
||||
minor: u32,
|
||||
toolchain: Toolchain,
|
||||
}
|
||||
|
||||
fn rustc_version_info() -> Option<VersionInfo> {
|
||||
let rustc = env::var_os("RUSTC").unwrap_or_else(|| OsString::from("rustc"));
|
||||
let output = Command::new(rustc).arg("--version").output().ok()?;
|
||||
let version = str::from_utf8(&output.stdout).ok()?;
|
||||
let mut pieces = version.split('.');
|
||||
if pieces.next() != Some("rustc 1") {
|
||||
let mut pieces = version.split(['.', ' ', '-']);
|
||||
if pieces.next() != Some("rustc") {
|
||||
return None;
|
||||
}
|
||||
pieces.next()?.parse().ok()
|
||||
let _major: u32 = pieces.next()?.parse().ok()?;
|
||||
let minor = pieces.next()?.parse().ok()?;
|
||||
let _patch: u32 = pieces.next()?.parse().ok()?;
|
||||
let toolchain = match pieces.next() {
|
||||
Some("beta") => Toolchain::Beta,
|
||||
Some("nightly") => Toolchain::Nightly,
|
||||
_ => Toolchain::Stable,
|
||||
};
|
||||
let version = VersionInfo { minor, toolchain };
|
||||
Some(version)
|
||||
}
|
||||
|
136
eyre/src/lib.rs
136
eyre/src/lib.rs
@ -236,23 +236,9 @@
|
||||
//!
|
||||
//! ## No-std support
|
||||
//!
|
||||
//! **NOTE**: tests are currently broken for `no_std` so I cannot guarantee that
|
||||
//! everything works still. I'm waiting for upstream fixes to be merged rather than
|
||||
//! fixing them myself, so bear with me.
|
||||
//!
|
||||
//! In no_std mode, almost all the API is available and works the same way. To
|
||||
//! depend on Eyre in no_std mode, disable our default enabled "std" feature in
|
||||
//! Cargo.toml. A global allocator is required.
|
||||
//!
|
||||
//! ```toml
|
||||
//! [dependencies]
|
||||
//! eyre = { version = "0.6", default-features = false }
|
||||
//! ```
|
||||
//!
|
||||
//! Since the `?`-based error conversions would normally rely on the
|
||||
//! `std::error::Error` trait which is only available through std, no_std mode will
|
||||
//! require an explicit `.map_err(Report::msg)` when working with a non-Eyre error
|
||||
//! type inside a function that returns Eyre's error type.
|
||||
//! No-std support was removed in 2020 in [commit 608a16a] due to unaddressed upstream breakages.
|
||||
//! [commit 608a16a]:
|
||||
//! https://github.com/eyre-rs/eyre/pull/29/commits/608a16aa2c2c27eca6c88001cc94c6973c18f1d5
|
||||
//!
|
||||
//! ## Comparison to failure
|
||||
//!
|
||||
@ -287,27 +273,31 @@
|
||||
//! `source`. With `Option` there is no source error to wrap, so `wrap_err` ends up
|
||||
//! being somewhat meaningless.
|
||||
//!
|
||||
//! Instead `eyre` intends for users to use the combinator functions provided by
|
||||
//! `std` for converting `Option`s to `Result`s. So where you would write this with
|
||||
//! Instead `eyre` offers [`OptionExt::ok_or_eyre`] to yield _static_ errors from `None`,
|
||||
//! and intends for users to use the combinator functions provided by
|
||||
//! `std`, converting `Option`s to `Result`s, for _dynamic_ errors.
|
||||
//! So where you would write this with
|
||||
//! anyhow:
|
||||
//!
|
||||
//! ```rust
|
||||
//! use anyhow::Context;
|
||||
//!
|
||||
//! let opt: Option<()> = None;
|
||||
//! let result = opt.context("new error message");
|
||||
//! let result_static = opt.context("static error message");
|
||||
//! let result_dynamic = opt.with_context(|| format!("{} error message", "dynamic"));
|
||||
//! ```
|
||||
//!
|
||||
//! With `eyre` we want users to write:
|
||||
//!
|
||||
//! ```rust
|
||||
//! use eyre::{eyre, Result};
|
||||
//! use eyre::{eyre, OptionExt, Result};
|
||||
//!
|
||||
//! # #[cfg(not(feature = "auto-install"))]
|
||||
//! # eyre::set_hook(Box::new(eyre::DefaultHandler::default_with)).unwrap();
|
||||
//! #
|
||||
//! let opt: Option<()> = None;
|
||||
//! let result: Result<()> = opt.ok_or_else(|| eyre!("new error message"));
|
||||
//! let result_static: Result<()> = opt.ok_or_eyre("static error message");
|
||||
//! let result_dynamic: Result<()> = opt.ok_or_else(|| eyre!("{} error message", "dynamic"));
|
||||
//! ```
|
||||
//!
|
||||
//! **NOTE**: However, to help with porting we do provide a `ContextCompat` trait which
|
||||
@ -328,12 +318,15 @@
|
||||
//! [`simple-eyre`]: https://github.com/eyre-rs/simple-eyre
|
||||
//! [`color-spantrace`]: https://github.com/eyre-rs/color-spantrace
|
||||
//! [`color-backtrace`]: https://github.com/athre0z/color-backtrace
|
||||
#![doc(html_root_url = "https://docs.rs/eyre/0.6.8")]
|
||||
#![doc(html_root_url = "https://docs.rs/eyre/0.6.10")]
|
||||
#![cfg_attr(
|
||||
nightly,
|
||||
feature(rustdoc_missing_doc_code_examples),
|
||||
warn(rustdoc::missing_doc_code_examples)
|
||||
)]
|
||||
#![warn(
|
||||
missing_debug_implementations,
|
||||
missing_docs,
|
||||
// FIXME: this lint is currently nightly only
|
||||
rustdoc::missing_doc_code_examples,
|
||||
unsafe_op_in_unsafe_fn,
|
||||
rust_2018_idioms,
|
||||
unreachable_pub,
|
||||
@ -345,7 +338,6 @@
|
||||
overflowing_literals,
|
||||
path_statements,
|
||||
patterns_in_fns_without_body,
|
||||
private_in_public,
|
||||
unconditional_recursion,
|
||||
unused,
|
||||
unused_allocation,
|
||||
@ -371,12 +363,13 @@ mod error;
|
||||
mod fmt;
|
||||
mod kind;
|
||||
mod macros;
|
||||
mod option;
|
||||
mod ptr;
|
||||
mod wrapper;
|
||||
|
||||
use crate::backtrace::Backtrace;
|
||||
use crate::error::ErrorImpl;
|
||||
use core::fmt::Display;
|
||||
use core::fmt::{Debug, Display};
|
||||
|
||||
use std::error::Error as StdError;
|
||||
|
||||
@ -721,7 +714,7 @@ pub trait EyreHandler: core::any::Any + Send + Sync {
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
Result::Ok(())
|
||||
}
|
||||
|
||||
/// Store the location of the caller who constructed this error report
|
||||
@ -843,7 +836,7 @@ impl EyreHandler for DefaultHandler {
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
Result::Ok(())
|
||||
}
|
||||
|
||||
#[cfg(track_caller)]
|
||||
@ -1096,6 +1089,13 @@ pub type Result<T, E = Report> = core::result::Result<T, E>;
|
||||
/// # panic!("expected downcast to succeed");
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// # `wrap_err` vs `wrap_err_with`
|
||||
///
|
||||
/// `wrap_err` incurs a runtime cost even in the non-error case because it requires eagerly
|
||||
/// constructing the error object. `wrap_err_with` avoids this cost through lazy evaluation. This
|
||||
/// cost is proportional to the cost of the currently installed [`EyreHandler`]'s creation step.
|
||||
/// `wrap_err` is useful in cases where an constructed error object already exists.
|
||||
pub trait WrapErr<T, E>: context::private::Sealed {
|
||||
/// Wrap the error value with a new adhoc error
|
||||
#[cfg_attr(track_caller, track_caller)]
|
||||
@ -1125,6 +1125,61 @@ pub trait WrapErr<T, E>: context::private::Sealed {
|
||||
F: FnOnce() -> D;
|
||||
}
|
||||
|
||||
/// Provides the [`ok_or_eyre`][OptionExt::ok_or_eyre] method for [`Option`].
|
||||
///
|
||||
/// This trait is sealed and cannot be implemented for types outside of
|
||||
/// `eyre`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # #[cfg(not(feature = "auto-install"))]
|
||||
/// # eyre::set_hook(Box::new(eyre::DefaultHandler::default_with)).unwrap();
|
||||
/// use eyre::OptionExt;
|
||||
///
|
||||
/// let option: Option<()> = None;
|
||||
///
|
||||
/// let result = option.ok_or_eyre("static str error");
|
||||
///
|
||||
/// assert_eq!(result.unwrap_err().to_string(), "static str error");
|
||||
/// ```
|
||||
///
|
||||
/// # `ok_or_eyre` vs `ok_or_else`
|
||||
///
|
||||
/// If string interpolation is required for the generated [report][Report],
|
||||
/// use [`ok_or_else`][Option::ok_or_else] instead,
|
||||
/// invoking [`eyre!`] to perform string interpolation:
|
||||
///
|
||||
/// ```
|
||||
/// # #[cfg(not(feature = "auto-install"))]
|
||||
/// # eyre::set_hook(Box::new(eyre::DefaultHandler::default_with)).unwrap();
|
||||
/// use eyre::eyre;
|
||||
///
|
||||
/// let option: Option<()> = None;
|
||||
///
|
||||
/// let result = option.ok_or_else(|| eyre!("{} error", "dynamic"));
|
||||
///
|
||||
/// assert_eq!(result.unwrap_err().to_string(), "dynamic error");
|
||||
/// ```
|
||||
///
|
||||
/// `ok_or_eyre` incurs no runtime cost, as the error object
|
||||
/// is constructed from the provided static argument
|
||||
/// only in the `None` case.
|
||||
pub trait OptionExt<T>: context::private::Sealed {
|
||||
/// Transform the [`Option<T>`] into a [`Result<T, E>`],
|
||||
/// mapping [`Some(v)`][Option::Some] to [`Ok(v)`][Result::Ok]
|
||||
/// and [`None`] to [`Report`].
|
||||
///
|
||||
/// `ok_or_eyre` allows for eyre [`Report`] error objects
|
||||
/// to be lazily created from static messages in the `None` case.
|
||||
///
|
||||
/// For dynamic error messages, use [`ok_or_else`][Option::ok_or_else],
|
||||
/// invoking [`eyre!`] in the closure to perform string interpolation.
|
||||
fn ok_or_eyre<M>(self, message: M) -> crate::Result<T>
|
||||
where
|
||||
M: Debug + Display + Send + Sync + 'static;
|
||||
}
|
||||
|
||||
/// Provides the `context` method for `Option` when porting from `anyhow`
|
||||
///
|
||||
/// This trait is sealed and cannot be implemented for types outside of
|
||||
@ -1198,6 +1253,29 @@ pub trait ContextCompat<T>: context::private::Sealed {
|
||||
F: FnOnce() -> D;
|
||||
}
|
||||
|
||||
/// Equivalent to Ok::<_, eyre::Error>(value).
|
||||
///
|
||||
/// This simplifies creation of an eyre::Result in places where type inference
|
||||
/// cannot deduce the `E` type of the result — without needing to write
|
||||
/// `Ok::<_, eyre::Error>(value)`.
|
||||
///
|
||||
/// One might think that `eyre::Result::Ok(value)` would work in such cases
|
||||
/// but it does not.
|
||||
///
|
||||
/// ```console
|
||||
/// error[E0282]: type annotations needed for `std::result::Result<i32, E>`
|
||||
/// --> src/main.rs:11:13
|
||||
/// |
|
||||
/// 11 | let _ = eyre::Result::Ok(1);
|
||||
/// | - ^^^^^^^^^^^^^^^^ cannot infer type for type parameter `E` declared on the enum `Result`
|
||||
/// | |
|
||||
/// | consider giving this pattern the explicit type `std::result::Result<i32, E>`, where the type parameter `E` is specified
|
||||
/// ```
|
||||
#[allow(non_snake_case)]
|
||||
pub fn Ok<T>(t: T) -> Result<T> {
|
||||
Result::Ok(t)
|
||||
}
|
||||
|
||||
// Not public API. Referenced by macro-generated code.
|
||||
#[doc(hidden)]
|
||||
pub mod private {
|
||||
|
@ -1,6 +1,6 @@
|
||||
/// Return early with an error.
|
||||
///
|
||||
/// This macro is equivalent to `return Err(From::from($err))`.
|
||||
/// This macro is equivalent to `return Err(eyre!(<args>))`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
@ -51,22 +51,22 @@
|
||||
#[macro_export]
|
||||
macro_rules! bail {
|
||||
($msg:literal $(,)?) => {
|
||||
return $crate::private::Err($crate::eyre!($msg));
|
||||
return $crate::private::Err($crate::eyre!($msg).into());
|
||||
};
|
||||
($err:expr $(,)?) => {
|
||||
return $crate::private::Err($crate::eyre!($err));
|
||||
return $crate::private::Err($crate::eyre!($err).into());
|
||||
};
|
||||
($fmt:expr, $($arg:tt)*) => {
|
||||
return $crate::private::Err($crate::eyre!($fmt, $($arg)*));
|
||||
return $crate::private::Err($crate::eyre!($fmt, $($arg)*).into());
|
||||
};
|
||||
}
|
||||
|
||||
/// Return early with an error if a condition is not satisfied.
|
||||
///
|
||||
/// This macro is equivalent to `if !$cond { return Err(From::from($err)); }`.
|
||||
/// This macro is equivalent to `if !$cond { return Err(eyre!(<other args>)); }`.
|
||||
///
|
||||
/// Analogously to `assert!`, `ensure!` takes a condition and exits the function
|
||||
/// if the condition fails. Unlike `assert!`, `ensure!` returns an `Error`
|
||||
/// if the condition fails. Unlike `assert!`, `ensure!` returns an `eyre::Result`
|
||||
/// rather than panicking.
|
||||
///
|
||||
/// # Example
|
||||
@ -107,26 +107,31 @@ macro_rules! bail {
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! ensure {
|
||||
($cond:expr $(,)?) => {
|
||||
if !$cond {
|
||||
$crate::ensure!($cond, concat!("Condition failed: `", stringify!($cond), "`"))
|
||||
}
|
||||
};
|
||||
($cond:expr, $msg:literal $(,)?) => {
|
||||
if !$cond {
|
||||
return $crate::private::Err($crate::eyre!($msg));
|
||||
return $crate::private::Err($crate::eyre!($msg).into());
|
||||
}
|
||||
};
|
||||
($cond:expr, $err:expr $(,)?) => {
|
||||
if !$cond {
|
||||
return $crate::private::Err($crate::eyre!($err));
|
||||
return $crate::private::Err($crate::eyre!($err).into());
|
||||
}
|
||||
};
|
||||
($cond:expr, $fmt:expr, $($arg:tt)*) => {
|
||||
if !$cond {
|
||||
return $crate::private::Err($crate::eyre!($fmt, $($arg)*));
|
||||
return $crate::private::Err($crate::eyre!($fmt, $($arg)*).into());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Construct an ad-hoc error from a string.
|
||||
///
|
||||
/// This evaluates to an `Error`. It can take either just a string, or a format
|
||||
/// This evaluates to a `Report`. It can take either just a string, or a format
|
||||
/// string with arguments. It also can take any custom type which implements
|
||||
/// `Debug` and `Display`.
|
||||
///
|
||||
|
14
eyre/src/option.rs
Normal file
14
eyre/src/option.rs
Normal file
@ -0,0 +1,14 @@
|
||||
use crate::OptionExt;
|
||||
use core::fmt::{Debug, Display};
|
||||
|
||||
impl<T> OptionExt<T> for Option<T> {
|
||||
fn ok_or_eyre<M>(self, message: M) -> crate::Result<T>
|
||||
where
|
||||
M: Debug + Display + Send + Sync + 'static,
|
||||
{
|
||||
match self {
|
||||
Some(ok) => Ok(ok),
|
||||
None => Err(crate::Report::msg(message)),
|
||||
}
|
||||
}
|
||||
}
|
@ -39,6 +39,34 @@ fn test_ensure() {
|
||||
Ok(())
|
||||
};
|
||||
assert!(f().is_err());
|
||||
|
||||
// Tests single-argument `ensure!`
|
||||
let f = || -> Result<()> {
|
||||
ensure!(v + v == 1);
|
||||
Ok(())
|
||||
};
|
||||
assert_eq!(
|
||||
f().unwrap_err().to_string(),
|
||||
"Condition failed: `v + v == 1`",
|
||||
);
|
||||
|
||||
// Tests automatically converting to external errors with ensure!()
|
||||
let f = || -> Result<(), SomeWrappingErr> {
|
||||
ensure!(false, "this will fail");
|
||||
Ok(())
|
||||
};
|
||||
assert!(f().is_err());
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
struct SomeWrappingErr {
|
||||
err: eyre::Error,
|
||||
}
|
||||
|
||||
impl From<eyre::Error> for SomeWrappingErr {
|
||||
fn from(err: eyre::Error) -> Self {
|
||||
SomeWrappingErr { err }
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
15
eyre/tests/test_option.rs
Normal file
15
eyre/tests/test_option.rs
Normal file
@ -0,0 +1,15 @@
|
||||
mod common;
|
||||
|
||||
use self::common::maybe_install_handler;
|
||||
use eyre::OptionExt;
|
||||
|
||||
#[test]
|
||||
fn test_option_ok_or_eyre() {
|
||||
maybe_install_handler().unwrap();
|
||||
|
||||
let option: Option<()> = None;
|
||||
|
||||
let result = option.ok_or_eyre("static str error");
|
||||
|
||||
assert_eq!(result.unwrap_err().to_string(), "static str error");
|
||||
}
|
@ -28,6 +28,6 @@ fn test_pyo3_exception_contents() {
|
||||
Python::with_gil(|py| {
|
||||
let locals = [("err", pyerr)].into_py_dict(py);
|
||||
let pyerr = py.run("raise err", None, Some(locals)).unwrap_err();
|
||||
assert_eq!(pyerr.pvalue(py).to_string(), expected_contents);
|
||||
assert_eq!(pyerr.value(py).to_string(), expected_contents);
|
||||
})
|
||||
}
|
||||
|
34
eyre/tests/test_toolchain.rs
Normal file
34
eyre/tests/test_toolchain.rs
Normal file
@ -0,0 +1,34 @@
|
||||
// These tests check our build script against rustversion.
|
||||
|
||||
#[rustversion::attr(not(nightly), ignore)]
|
||||
#[test]
|
||||
fn nightlytest() {
|
||||
if !cfg!(nightly) {
|
||||
panic!("nightly feature isn't set when the toolchain is nightly.");
|
||||
}
|
||||
if cfg!(any(beta, stable)) {
|
||||
panic!("beta, stable, and nightly are mutually exclusive features.")
|
||||
}
|
||||
}
|
||||
|
||||
#[rustversion::attr(not(beta), ignore)]
|
||||
#[test]
|
||||
fn betatest() {
|
||||
if !cfg!(beta) {
|
||||
panic!("beta feature is not set when the toolchain is beta.");
|
||||
}
|
||||
if cfg!(any(nightly, stable)) {
|
||||
panic!("beta, stable, and nightly are mutually exclusive features.")
|
||||
}
|
||||
}
|
||||
|
||||
#[rustversion::attr(not(stable), ignore)]
|
||||
#[test]
|
||||
fn stabletest() {
|
||||
if !cfg!(stable) {
|
||||
panic!("stable feature is not set when the toolchain is stable.");
|
||||
}
|
||||
if cfg!(any(nightly, beta)) {
|
||||
panic!("beta, stable, and nightly are mutually exclusive features.")
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user