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 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 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}