mirror of
https://github.com/eyre-rs/eyre.git
synced 2025-09-27 04:50:50 +00:00
Extend Option
with ok_or_eyre
(#129)
Previously, a closure and macro invocation was required to generate a static string error object from an `Option::None`. This change adds an extension trait, providing the `ok_or_eyre` method on the `Option` type. `Option::ok_or_eyre` accepts static error messages and creates `Report` objects lazily in the `None` case. Implements #125
This commit is contained in:
parent
da84e8c624
commit
4e1f323d31
16
README.md
16
README.md
@ -208,24 +208,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
|
||||
|
@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
<!-- next-header -->
|
||||
|
||||
## [Unreleased] - ReleaseDate
|
||||
### Added
|
||||
- Add `OptionExt::ok_or_eyre` for yielding static `Report`s from `None` [by LeoniePhiline](https://github.com/eyre-rs/eyre/pull/125)
|
||||
|
||||
## [0.6.9] - 2023-11-17
|
||||
### Fixed
|
||||
|
@ -273,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
|
||||
@ -359,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;
|
||||
|
||||
@ -1120,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
|
||||
|
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)),
|
||||
}
|
||||
}
|
||||
}
|
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");
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user