err_with/lib.rs
1//! This crate provides a single trait, `ErrWith`, with one method,
2//! `err_with`. `ErrWith` is implemented for `Result<T, E>`, with
3//! `result.err_with(w)` transforming an `Err(e)` to an `Err((e,w))`,
4//! and leaving an `Ok(...)` unchanged.
5//!
6//! This is not particularly useful on its own, but can be used to
7//! define conversions from `(E, W)` into your custom error types, so
8//! error contexts can be recorded and reported later.
9//!
10//! For example:
11//!
12//! ```no_run
13//! use std::{fs, io, path::{Path, PathBuf}};
14//!
15//! use err_with::ErrWith;
16//!
17//! // Given this custom error type:
18//! #[derive(Debug)]
19//! enum Error {
20//! Io { io_error: io::Error, path: PathBuf },
21//! }
22//!
23//! // We can define a conversion from `(io::Error, AsRef<Path>)` to our
24//! // custom error type:
25//! impl<P: AsRef<Path>> From<(io::Error, P)> for Error {
26//! fn from((io_error, path): (io::Error, P)) -> Error {
27//! Error::Io {
28//! path: path.as_ref().to_owned(),
29//! io_error,
30//! }
31//! }
32//! }
33//!
34//! // Which allows us to attach the path of an I/O error and convert
35//! // the error into our custom error type in an ergonomic fashion:
36//! fn main() -> Result<(), Error> {
37//! fs::read_to_string("foo/bar").err_with("foo/bar")?;
38//! Ok(())
39//! }
40//! ```
41//!
42
43pub trait ErrWith<T, E> {
44 fn err_with<W>(self, with: W) -> Result<T, (E, W)>;
45}
46
47impl<T, E> ErrWith<T, E> for Result<T, E> {
48 fn err_with<W>(self, with: W) -> Result<T, (E, W)> {
49 match self {
50 Ok(ok) => Ok(ok),
51 Err(error) => Err((error, with)),
52 }
53 }
54}