Support context on Option

This commit is contained in:
David Tolnay 2019-10-08 01:24:18 -07:00
parent c06155e5fb
commit aa2d08087c
No known key found for this signature in database
GPG Key ID: F9BA143B95FF6D82
3 changed files with 74 additions and 1 deletions

View File

@ -9,5 +9,5 @@ script: cargo test
matrix:
include:
- rust: 1.32.0
- rust: 1.34.0
script: cargo check

View File

@ -1,4 +1,5 @@
use crate::Error;
use std::convert::Infallible;
use std::error::Error as StdError;
use std::fmt::{self, Debug, Display};
@ -103,6 +104,43 @@ impl<T> Context<T, Error> for Result<T, Error> {
}
}
/// ```
/// # type T = ();
/// #
/// use anyhow::{Context, Result};
///
/// fn maybe_get() -> Option<T> {
/// # const IGNORE: &str = stringify! {
/// ...
/// # };
/// # unimplemented!()
/// }
///
/// fn demo() -> Result<()> {
/// let t = maybe_get().context("there is no T")?;
/// # const IGNORE: &str = stringify! {
/// ...
/// # };
/// # unimplemented!()
/// }
/// ```
impl<T> Context<T, Infallible> for Option<T> {
fn context<C>(self, context: C) -> Result<T, Error>
where
C: Display + Send + Sync + 'static,
{
self.ok_or_else(|| Error::from_display(context, backtrace!()))
}
fn with_context<C, F>(self, context: F) -> Result<T, Error>
where
C: Display + Send + Sync + 'static,
F: FnOnce() -> C,
{
self.ok_or_else(|| Error::from_display(context(), backtrace!()))
}
}
pub(crate) struct ContextError<E, C> {
pub error: E,
pub context: C,

View File

@ -59,6 +59,18 @@ impl Error {
unsafe { Error::construct(error, type_id, backtrace) }
}
pub(crate) fn from_display<M>(message: M, backtrace: Option<Backtrace>) -> Self
where
M: Display + Send + Sync + 'static,
{
let error = DisplayError(message);
let type_id = TypeId::of::<M>();
// Safety: DisplayError is repr(transparent) so DisplayError<M> has the
// same layout as the typeid specifies.
unsafe { Error::construct(error, type_id, backtrace) }
}
// Takes backtrace as argument rather than capturing it here so that the
// user sees one fewer layer of wrapping noise in the backtrace.
//
@ -424,6 +436,29 @@ where
impl<M> StdError for MessageError<M> where M: Display + Debug + 'static {}
#[repr(transparent)]
struct DisplayError<M>(M);
impl<M> Debug for DisplayError<M>
where
M: Display,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Display::fmt(&self.0, f)
}
}
impl<M> Display for DisplayError<M>
where
M: Display,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Display::fmt(&self.0, f)
}
}
impl<M> StdError for DisplayError<M> where M: Display + 'static {}
impl ErrorImpl<()> {
fn error(&self) -> &(dyn StdError + Send + Sync + 'static) {
unsafe { &*(self.vtable.object)(&self.error) }