feat: add annotate() method to Context

to just annotate the passed error with location data

Signed-off-by: Harald Hoyer <harald@hoyer.xyz>
This commit is contained in:
Harald Hoyer 2023-07-28 17:06:10 +02:00
parent 101d2074e1
commit 46b7f58e72
Signed by: harald
GPG key ID: 900F3C4971086004
2 changed files with 38 additions and 2 deletions

View file

@ -1,4 +1,4 @@
use chainerror::prelude::v2::*; use chainerror::Context as _;
use std::error::Error; use std::error::Error;
use std::fmt; use std::fmt;
use std::io; use std::io;
@ -8,12 +8,17 @@ fn do_some_io() -> Result<(), Box<dyn Error + Send + Sync>> {
Ok(()) Ok(())
} }
fn func3() -> Result<(), Box<dyn Error + Send + Sync>> { fn func4() -> Result<(), Box<dyn Error + Send + Sync>> {
let filename = "foo.txt"; let filename = "foo.txt";
do_some_io().context(format!("Error reading '{}'", filename))?; do_some_io().context(format!("Error reading '{}'", filename))?;
Ok(()) Ok(())
} }
fn func3() -> Result<(), Box<dyn Error + Send + Sync>> {
func4().annotate()?;
Ok(())
}
chainerror::str_context!(Func2Error); chainerror::str_context!(Func2Error);
fn func2() -> chainerror::Result<(), Func2Error> { fn func2() -> chainerror::Result<(), Func2Error> {

View file

@ -216,6 +216,9 @@ pub trait Context<O, E: Into<Box<dyn StdError + 'static + Send + Sync>>> {
/// Decorate the error with a `kind` of type `T` and the source `Location` /// Decorate the error with a `kind` of type `T` and the source `Location`
fn context<T: 'static + Display + Debug>(self, kind: T) -> std::result::Result<O, Error<T>>; fn context<T: 'static + Display + Debug>(self, kind: T) -> std::result::Result<O, Error<T>>;
/// Decorate the error just with the source `Location`
fn annotate(self) -> std::result::Result<O, Error<AnnotatedError>>;
/// Decorate the `error` with a `kind` of type `T` produced with a `FnOnce(&error)` and the source `Location` /// Decorate the `error` with a `kind` of type `T` produced with a `FnOnce(&error)` and the source `Location`
fn map_context<T: 'static + Display + Debug, F: FnOnce(&E) -> T>( fn map_context<T: 'static + Display + Debug, F: FnOnce(&E) -> T>(
self, self,
@ -223,6 +226,21 @@ pub trait Context<O, E: Into<Box<dyn StdError + 'static + Send + Sync>>> {
) -> std::result::Result<O, Error<T>>; ) -> std::result::Result<O, Error<T>>;
} }
/// Convenience type to just decorate the error with the source `Location`
pub struct AnnotatedError(());
impl Display for AnnotatedError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "(passed error)")
}
}
impl Debug for AnnotatedError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "(passed error)")
}
}
impl<O, E: Into<Box<dyn StdError + 'static + Send + Sync>>> Context<O, E> impl<O, E: Into<Box<dyn StdError + 'static + Send + Sync>>> Context<O, E>
for std::result::Result<O, E> for std::result::Result<O, E>
{ {
@ -239,6 +257,19 @@ impl<O, E: Into<Box<dyn StdError + 'static + Send + Sync>>> Context<O, E>
} }
} }
#[track_caller]
#[inline]
fn annotate(self) -> std::result::Result<O, Error<AnnotatedError>> {
match self {
Ok(t) => Ok(t),
Err(error_cause) => Err(Error::new(
AnnotatedError(()),
Some(error_cause.into()),
Some(Location::caller().to_string()),
)),
}
}
#[track_caller] #[track_caller]
#[inline] #[inline]
fn map_context<T: 'static + Display + Debug, F: FnOnce(&E) -> T>( fn map_context<T: 'static + Display + Debug, F: FnOnce(&E) -> T>(