1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
use crate::{api_error::ApiError, json::JsonError, response::StatusCode};
use hyper::{Body, Response};
use std::{
error::Error as StdError,
fmt::{Debug, Display, Formatter, Result as FmtResult},
str,
};
#[derive(Debug)]
pub struct Error {
pub(super) source: Option<Box<dyn StdError + Send + Sync>>,
pub(super) kind: ErrorType,
}
impl Error {
#[must_use = "retrieving the type has no effect if left unused"]
pub const fn kind(&self) -> &ErrorType {
&self.kind
}
#[must_use = "consuming the error and retrieving the source has no effect if left unused"]
pub fn into_source(self) -> Option<Box<dyn StdError + Send + Sync>> {
self.source
}
#[must_use = "consuming the error into its parts has no effect if left unused"]
pub fn into_parts(self) -> (ErrorType, Option<Box<dyn StdError + Send + Sync>>) {
(self.kind, self.source)
}
pub(super) fn json(source: JsonError) -> Self {
Self {
kind: ErrorType::Json,
source: Some(Box::new(source)),
}
}
}
impl Display for Error {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
match &self.kind {
ErrorType::BuildingRequest => f.write_str("failed to build the request"),
ErrorType::ChunkingResponse => f.write_str("Chunking the response failed"),
ErrorType::CreatingHeader { name, .. } => {
f.write_str("Parsing the value for header {}")?;
f.write_str(name)?;
f.write_str(" failed")
}
ErrorType::Json => f.write_str("Given value couldn't be serialized"),
ErrorType::Parsing { body, .. } => {
f.write_str("Response body couldn't be deserialized: ")?;
if let Ok(body) = str::from_utf8(body) {
f.write_str(body)
} else {
Debug::fmt(body, f)
}
}
ErrorType::RatelimiterTicket => f.write_str("Failed to get ratelimiter ticket"),
ErrorType::RequestCanceled => {
f.write_str("Request was canceled either before or while being sent")
}
ErrorType::RequestError => f.write_str("Parsing or sending the response failed"),
ErrorType::RequestTimedOut => f.write_str("request timed out"),
ErrorType::Response { error, status, .. } => {
f.write_str("Response error: status code ")?;
Display::fmt(status, f)?;
f.write_str(", error: ")?;
Display::fmt(error, f)
}
ErrorType::ServiceUnavailable { .. } => {
f.write_str("api may be temporarily unavailable (received a 503)")
}
ErrorType::Unauthorized => {
f.write_str("token in use is invalid, expired, or is revoked")
}
}
}
}
impl StdError for Error {
fn source(&self) -> Option<&(dyn StdError + 'static)> {
self.source
.as_ref()
.map(|source| &**source as &(dyn StdError + 'static))
}
}
#[derive(Debug)]
#[non_exhaustive]
pub enum ErrorType {
BuildingRequest,
ChunkingResponse,
CreatingHeader {
name: String,
},
Json,
Parsing {
body: Vec<u8>,
},
RatelimiterTicket,
RequestCanceled,
RequestError,
RequestTimedOut,
Response {
body: Vec<u8>,
error: ApiError,
status: StatusCode,
},
ServiceUnavailable {
response: Response<Body>,
},
Unauthorized,
}