client_util/
error.rs

1use std::{borrow::Cow, fmt};
2
3pub type Result<T> = std::result::Result<T, Error>;
4
5#[derive(Debug)]
6pub struct Error {
7    kind: ErrorKind,
8    context: Cow<'static, str>,
9}
10
11impl From<http::Error> for Error {
12    fn from(val: http::Error) -> Self {
13        Error::new(ErrorKind::Http(val), "unknown")
14    }
15}
16
17#[derive(Debug)]
18pub struct BodyError(pub(crate) Box<dyn std::error::Error + Send + Sync + 'static>);
19
20impl std::fmt::Display for BodyError {
21    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
22        write!(f, "{}", self.0)
23    }
24}
25
26impl std::error::Error for BodyError {}
27#[derive(Debug)]
28pub struct ClientError(Box<dyn std::error::Error + Send + Sync + 'static>);
29
30impl<E> From<E> for ClientError
31where
32    E: std::error::Error + Send + Sync + 'static,
33{
34    fn from(val: E) -> Self {
35        ClientError(Box::new(val))
36    }
37}
38
39impl From<ClientError> for Box<dyn std::error::Error + Send + Sync> {
40    fn from(val: ClientError) -> Self {
41        val.0
42    }
43}
44
45impl std::fmt::Display for ClientError {
46    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
47        write!(f, "{}", self.0)
48    }
49}
50
51impl Error {
52    pub fn new<E, C>(kind: E, context: C) -> Self
53    where
54        E: Into<ErrorKind>,
55        C: Into<Cow<'static, str>>,
56    {
57        Error {
58            kind: kind.into(),
59            context: context.into(),
60        }
61    }
62    /// Create a new error with a context.
63    pub fn with_context<C, K>(context: C) -> impl FnOnce(K) -> Self
64    where
65        C: Into<Cow<'static, str>>,
66        K: Into<ErrorKind>,
67    {
68        move |kind| Error {
69            kind: kind.into(),
70            context: context.into(),
71        }
72    }
73    /// Create a new custom error with a context.
74    pub fn custom_with_context<C, E>(context: C) -> impl FnOnce(E) -> Self
75    where
76        C: Into<Cow<'static, str>>,
77        E: std::error::Error + Send + 'static,
78    {
79        move |error| Error {
80            kind: ErrorKind::unknown(error),
81            context: context.into(),
82        }
83    }
84    pub fn kind(&self) -> &ErrorKind {
85        &self.kind
86    }
87
88    pub fn context(&self) -> &str {
89        &self.context
90    }
91
92    pub fn into_inner(self) -> ErrorKind {
93        self.kind
94    }
95}
96
97macro_rules! error_kinds {
98    ($Ident: ident {
99        $(
100            $(#[$meta:meta])*
101            $Variant: ident($Inner: ty)
102        ),* $(,)?
103    }) => {
104        #[derive(Debug)]
105        pub enum $Ident {
106            $(
107                $(#[$meta])*
108                $Variant($Inner),
109            )*
110        }
111        $(
112            $(#[$meta])*
113            impl From<$Inner> for $Ident {
114                fn from(val: $Inner) -> Self {
115                    $Ident::$Variant(val)
116                }
117            }
118        )*
119        impl fmt::Display for ErrorKind {
120            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
121                match self {
122                    $(
123                        $(#[$meta])*
124                        ErrorKind::$Variant(e) => {
125                            write!(f, "{}: {}", stringify!($Variant), e)
126                        }
127                    )*
128                }
129            }
130        }
131    };
132}
133
134error_kinds! {
135    ErrorKind {
136        Http(http::Error),
137        InvalidUri(http::uri::InvalidUri),
138        InvalidUriParts(http::uri::InvalidUriParts),
139        Utf8DecodeError(std::string::FromUtf8Error),
140        Unknown(Box<dyn std::error::Error + Send>),
141        MimeParse(mime::FromStrError),
142        InvalidHeaderValue(http::header::InvalidHeaderValue),
143        Body(BodyError),
144        Client(ClientError),
145        #[cfg(feature = "hyper")]
146        Hyper(hyper::Error),
147        #[cfg(feature = "serde_json")]
148        SerdeJson(serde_json::Error),
149        #[cfg(feature = "serde_urlencoded")]
150        SerdeUrlencoded(serde_urlencoded::ser::Error),
151    }
152}
153
154impl ErrorKind {
155    pub fn unknown<E>(error: E) -> Self
156    where
157        E: std::error::Error + Send + 'static,
158    {
159        ErrorKind::Unknown(Box::new(error))
160    }
161}
162
163impl fmt::Display for Error {
164    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
165        write!(f, "[{}] when [{}]", self.kind, self.context)
166    }
167}