|
273 | 273 | //! `source`. With `Option` there is no source error to wrap, so `wrap_err` ends up
|
274 | 274 | //! being somewhat meaningless.
|
275 | 275 | //!
|
276 |
| -//! Instead `eyre` intends for users to use the combinator functions provided by |
277 |
| -//! `std` for converting `Option`s to `Result`s. So where you would write this with |
| 276 | +//! Instead `eyre` offers [`OptionExt::ok_or_eyre`] to yield _static_ errors from `None`, |
| 277 | +//! and intends for users to use the combinator functions provided by |
| 278 | +//! `std`, converting `Option`s to `Result`s, for _dynamic_ errors. |
| 279 | +//! So where you would write this with |
278 | 280 | //! anyhow:
|
279 | 281 | //!
|
280 | 282 | //! ```rust
|
281 | 283 | //! use anyhow::Context;
|
282 | 284 | //!
|
283 | 285 | //! let opt: Option<()> = None;
|
284 |
| -//! let result = opt.context("new error message"); |
| 286 | +//! let result_static = opt.context("static error message"); |
| 287 | +//! let result_dynamic = opt.with_context(|| format!("{} error message", "dynamic")); |
285 | 288 | //! ```
|
286 | 289 | //!
|
287 | 290 | //! With `eyre` we want users to write:
|
288 | 291 | //!
|
289 | 292 | //! ```rust
|
290 |
| -//! use eyre::{eyre, Result}; |
| 293 | +//! use eyre::{eyre, OptionExt, Result}; |
291 | 294 | //!
|
292 | 295 | //! # #[cfg(not(feature = "auto-install"))]
|
293 | 296 | //! # eyre::set_hook(Box::new(eyre::DefaultHandler::default_with)).unwrap();
|
294 | 297 | //! #
|
295 | 298 | //! let opt: Option<()> = None;
|
296 |
| -//! let result: Result<()> = opt.ok_or_else(|| eyre!("new error message")); |
| 299 | +//! let result_static: Result<()> = opt.ok_or_eyre("static error message"); |
| 300 | +//! let result_dynamic: Result<()> = opt.ok_or_else(|| eyre!("{} error message", "dynamic")); |
297 | 301 | //! ```
|
298 | 302 | //!
|
299 | 303 | //! **NOTE**: However, to help with porting we do provide a `ContextCompat` trait which
|
@@ -359,12 +363,13 @@ mod error;
|
359 | 363 | mod fmt;
|
360 | 364 | mod kind;
|
361 | 365 | mod macros;
|
| 366 | +mod option; |
362 | 367 | mod ptr;
|
363 | 368 | mod wrapper;
|
364 | 369 |
|
365 | 370 | use crate::backtrace::Backtrace;
|
366 | 371 | use crate::error::ErrorImpl;
|
367 |
| -use core::fmt::Display; |
| 372 | +use core::fmt::{Debug, Display}; |
368 | 373 |
|
369 | 374 | use std::error::Error as StdError;
|
370 | 375 |
|
@@ -1120,6 +1125,61 @@ pub trait WrapErr<T, E>: context::private::Sealed {
|
1120 | 1125 | F: FnOnce() -> D;
|
1121 | 1126 | }
|
1122 | 1127 |
|
| 1128 | +/// Provides the [`ok_or_eyre`][OptionExt::ok_or_eyre] method for [`Option`]. |
| 1129 | +/// |
| 1130 | +/// This trait is sealed and cannot be implemented for types outside of |
| 1131 | +/// `eyre`. |
| 1132 | +/// |
| 1133 | +/// # Example |
| 1134 | +/// |
| 1135 | +/// ``` |
| 1136 | +/// # #[cfg(not(feature = "auto-install"))] |
| 1137 | +/// # eyre::set_hook(Box::new(eyre::DefaultHandler::default_with)).unwrap(); |
| 1138 | +/// use eyre::OptionExt; |
| 1139 | +/// |
| 1140 | +/// let option: Option<()> = None; |
| 1141 | +/// |
| 1142 | +/// let result = option.ok_or_eyre("static str error"); |
| 1143 | +/// |
| 1144 | +/// assert_eq!(result.unwrap_err().to_string(), "static str error"); |
| 1145 | +/// ``` |
| 1146 | +/// |
| 1147 | +/// # `ok_or_eyre` vs `ok_or_else` |
| 1148 | +/// |
| 1149 | +/// If string interpolation is required for the generated [report][Report], |
| 1150 | +/// use [`ok_or_else`][Option::ok_or_else] instead, |
| 1151 | +/// invoking [`eyre!`] to perform string interpolation: |
| 1152 | +/// |
| 1153 | +/// ``` |
| 1154 | +/// # #[cfg(not(feature = "auto-install"))] |
| 1155 | +/// # eyre::set_hook(Box::new(eyre::DefaultHandler::default_with)).unwrap(); |
| 1156 | +/// use eyre::eyre; |
| 1157 | +/// |
| 1158 | +/// let option: Option<()> = None; |
| 1159 | +/// |
| 1160 | +/// let result = option.ok_or_else(|| eyre!("{} error", "dynamic")); |
| 1161 | +/// |
| 1162 | +/// assert_eq!(result.unwrap_err().to_string(), "dynamic error"); |
| 1163 | +/// ``` |
| 1164 | +/// |
| 1165 | +/// `ok_or_eyre` incurs no runtime cost, as the error object |
| 1166 | +/// is constructed from the provided static argument |
| 1167 | +/// only in the `None` case. |
| 1168 | +pub trait OptionExt<T>: context::private::Sealed { |
| 1169 | + /// Transform the [`Option<T>`] into a [`Result<T, E>`], |
| 1170 | + /// mapping [`Some(v)`][Option::Some] to [`Ok(v)`][Result::Ok] |
| 1171 | + /// and [`None`] to [`Report`]. |
| 1172 | + /// |
| 1173 | + /// `ok_or_eyre` allows for eyre [`Report`] error objects |
| 1174 | + /// to be lazily created from static messages in the `None` case. |
| 1175 | + /// |
| 1176 | + /// For dynamic error messages, use [`ok_or_else`][Option::ok_or_else], |
| 1177 | + /// invoking [`eyre!`] in the closure to perform string interpolation. |
| 1178 | + fn ok_or_eyre<M>(self, message: M) -> crate::Result<T> |
| 1179 | + where |
| 1180 | + M: Debug + Display + Send + Sync + 'static; |
| 1181 | +} |
| 1182 | + |
1123 | 1183 | /// Provides the `context` method for `Option` when porting from `anyhow`
|
1124 | 1184 | ///
|
1125 | 1185 | /// This trait is sealed and cannot be implemented for types outside of
|
|
0 commit comments