1use std::error::Error as StdError;
5use std::fmt::Display;
6
7use thiserror::Error as ThisError;
8
9#[derive(Debug)]
14pub struct Error(ErrorKind);
15
16#[derive(Debug, ThisError)]
17enum ErrorKind {
18 #[error("{0}")]
19 Message(String),
20 #[error("{context}: {cause}")]
21 Context { context: String, cause: String },
22}
23
24pub type Result<T> = std::result::Result<T, Error>;
26
27impl Error {
28 pub fn msg(message: impl Into<String>) -> Self {
30 Self(ErrorKind::Message(message.into()))
31 }
32
33 #[must_use]
36 pub fn wrap_err(self, context: impl Display) -> Self {
37 Self(ErrorKind::Context {
38 context: context.to_string(),
39 cause: self.to_string(),
40 })
41 }
42
43 fn context_with_source(context: impl Display, source: impl Display) -> Self {
44 Self(ErrorKind::Context {
45 context: context.to_string(),
46 cause: source.to_string(),
47 })
48 }
49}
50
51pub trait Context<T> {
56 fn wrap_err(self, context: impl Display) -> Result<T>;
61 fn wrap_err_with<C>(self, context: impl FnOnce() -> C) -> Result<T>
67 where
68 C: Display;
69}
70
71impl<T, E> Context<T> for std::result::Result<T, E>
72where
73 E: Display,
74{
75 fn wrap_err(self, context: impl Display) -> Result<T> {
76 self.map_err(|source| Error::context_with_source(context, source))
77 }
78
79 fn wrap_err_with<C>(self, context: impl FnOnce() -> C) -> Result<T>
80 where
81 C: Display,
82 {
83 self.map_err(|source| Error::context_with_source(context(), source))
84 }
85}
86
87impl<E> From<E> for Error
88where
89 E: StdError + Send + Sync + 'static,
90{
91 fn from(value: E) -> Self {
92 Self::msg(value.to_string())
93 }
94}
95
96impl Display for Error {
97 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
98 self.0.fmt(formatter)
99 }
100}
101
102#[macro_export]
104macro_rules! stow_error {
105 ($($arg:tt)*) => {
106 $crate::error::Error::msg(format!($($arg)*))
107 };
108}