errctx/
lib.rs

1#![deny(missing_docs)]
2
3//! Wrapper for tacking on path context
4
5use std::{
6    error::Error,
7    fmt::{self, Debug, Display},
8    path::{Path, PathBuf},
9};
10
11/// Wrapper around an error providing additional context.
12#[derive(Debug)]
13pub struct ErrCtx<E, T> {
14    /// Inner error
15    pub inner: E,
16    /// Context associated with error
17    pub ctx: T,
18}
19
20impl<E: Error + 'static, T: Debug> Error for ErrCtx<E, T> {
21    fn source(&self) -> Option<&(dyn Error + 'static)> {
22        use thiserror::__private::AsDynError;
23        Some(self.inner.as_dyn_error())
24    }
25}
26
27impl<E, T> ErrCtx<E, T> {
28    /// Creates a new `ErrCtx` from an error and context type.
29    pub fn new(error: E, ctx: T) -> Self {
30        Self { inner: error, ctx }
31    }
32}
33
34impl<E, T: Debug> Display for ErrCtx<E, T> {
35    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
36        write!(f, "{:?}", self.ctx)
37    }
38}
39
40/// Additional path context for errors.
41pub type PathCtx<E> = ErrCtx<E, PathBuf>;
42
43impl<E> PathCtx<E> {
44    /// Convenience method that creates a closure which converts an `io::Error` to a `IoErrCtx`
45    ///
46    /// This is designed for simplifying the conversion of `io::Error`s using `.map_err`.
47    ///
48    /// For example
49    ///
50    /// ```
51    /// # use {std::{io, path::PathBuf}, errctx::PathCtx};
52    /// #
53    /// #   let res: Result<(), io::Error> = Err(io::Error::new(io::ErrorKind::Other, "oh no!"));
54    /// #   let path = PathBuf::from("example");
55    /// let res = res.map_err(|e| PathCtx::new(e, path));
56    /// #   assert_eq!(format!("{res:?}"), "Err(ErrCtx { inner: Custom { kind: Other, error: \"oh no!\" }, ctx: \"example\" })");
57    /// ```
58    ///
59    /// can become
60    ///
61    /// ```
62    /// # use {std::{io, path::PathBuf}, errctx::PathCtx};
63    /// #
64    /// #   let res: Result<(), io::Error> = Err(io::Error::new(io::ErrorKind::Other, "oh no!"));
65    /// #   let path = PathBuf::from("example");
66    /// let res = res.map_err(PathCtx::f(path));
67    /// #   assert_eq!(format!("{res:?}"), "Err(ErrCtx { inner: Custom { kind: Other, error: \"oh no!\" }, ctx: \"example\" })");
68    /// ```
69    pub fn f<P: AsRef<Path>>(path: P) -> Box<dyn FnOnce(E) -> Self> {
70        let p = path.as_ref().to_owned();
71        Box::new(|e| Self::new(e, p))
72    }
73}