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}