1use serde::{Deserialize, Serialize};
8use std::fmt::{self, Display, Formatter};
9
10#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
12#[serde(try_from = "u16", into = "u16")]
13pub struct StatusCode(reqwest::StatusCode);
14
15impl TryFrom<u16> for StatusCode {
16 type Error = <reqwest::StatusCode as TryFrom<u16>>::Error;
17
18 fn try_from(code: u16) -> Result<Self, Self::Error> {
19 Ok(reqwest::StatusCode::try_from(code)?.into())
20 }
21}
22
23impl From<StatusCode> for u16 {
24 fn from(code: StatusCode) -> Self {
25 code.0.as_u16()
26 }
27}
28
29impl TryFrom<StatusCode> for tide::StatusCode {
30 type Error = <tide::StatusCode as TryFrom<u16>>::Error;
31
32 fn try_from(code: StatusCode) -> Result<Self, Self::Error> {
33 u16::from(code).try_into()
36 }
37}
38
39impl From<tide::StatusCode> for StatusCode {
40 fn from(code: tide::StatusCode) -> Self {
41 u16::from(code).try_into().unwrap()
45 }
46}
47
48impl PartialEq<tide::StatusCode> for StatusCode {
49 fn eq(&self, other: &tide::StatusCode) -> bool {
50 *self == Self::from(*other)
51 }
52}
53
54impl PartialEq<StatusCode> for tide::StatusCode {
55 fn eq(&self, other: &StatusCode) -> bool {
56 StatusCode::from(*self) == *other
57 }
58}
59
60impl From<StatusCode> for reqwest::StatusCode {
61 fn from(code: StatusCode) -> Self {
62 code.0
63 }
64}
65
66impl From<reqwest::StatusCode> for StatusCode {
67 fn from(code: reqwest::StatusCode) -> Self {
68 Self(code)
69 }
70}
71
72impl PartialEq<reqwest::StatusCode> for StatusCode {
73 fn eq(&self, other: &reqwest::StatusCode) -> bool {
74 *self == Self::from(*other)
75 }
76}
77
78impl PartialEq<StatusCode> for reqwest::StatusCode {
79 fn eq(&self, other: &StatusCode) -> bool {
80 *self == Self::from(*other)
81 }
82}
83
84impl Display for StatusCode {
85 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
86 write!(f, "{}", u16::from(*self))
87 }
88}
89
90impl StatusCode {
91 pub fn is_informational(self) -> bool {
96 self.0.is_informational()
97 }
98
99 pub fn is_success(self) -> bool {
104 self.0.is_success()
105 }
106
107 pub fn is_redirection(self) -> bool {
112 self.0.is_redirection()
113 }
114
115 pub fn is_client_error(self) -> bool {
120 self.0.is_client_error()
121 }
122
123 pub fn is_server_error(self) -> bool {
128 self.0.is_server_error()
129 }
130
131 pub fn canonical_reason(self) -> Option<&'static str> {
133 self.0.canonical_reason()
134 }
135
136 pub const CONTINUE: Self = Self(reqwest::StatusCode::CONTINUE);
137 pub const SWITCHING_PROTOCOLS: Self = Self(reqwest::StatusCode::SWITCHING_PROTOCOLS);
138 pub const PROCESSING: Self = Self(reqwest::StatusCode::PROCESSING);
139 pub const OK: Self = Self(reqwest::StatusCode::OK);
140 pub const CREATED: Self = Self(reqwest::StatusCode::CREATED);
141 pub const ACCEPTED: Self = Self(reqwest::StatusCode::ACCEPTED);
142 pub const NON_AUTHORITATIVE_INFORMATION: Self =
143 Self(reqwest::StatusCode::NON_AUTHORITATIVE_INFORMATION);
144 pub const NO_CONTENT: Self = Self(reqwest::StatusCode::NO_CONTENT);
145 pub const RESET_CONTENT: Self = Self(reqwest::StatusCode::RESET_CONTENT);
146 pub const PARTIAL_CONTENT: Self = Self(reqwest::StatusCode::PARTIAL_CONTENT);
147 pub const MULTI_STATUS: Self = Self(reqwest::StatusCode::MULTI_STATUS);
148 pub const ALREADY_REPORTED: Self = Self(reqwest::StatusCode::ALREADY_REPORTED);
149 pub const IM_USED: Self = Self(reqwest::StatusCode::IM_USED);
150 pub const MULTIPLE_CHOICES: Self = Self(reqwest::StatusCode::MULTIPLE_CHOICES);
151 pub const MOVED_PERMANENTLY: Self = Self(reqwest::StatusCode::MOVED_PERMANENTLY);
152 pub const FOUND: Self = Self(reqwest::StatusCode::FOUND);
153 pub const SEE_OTHER: Self = Self(reqwest::StatusCode::SEE_OTHER);
154 pub const NOT_MODIFIED: Self = Self(reqwest::StatusCode::NOT_MODIFIED);
155 pub const USE_PROXY: Self = Self(reqwest::StatusCode::USE_PROXY);
156 pub const TEMPORARY_REDIRECT: Self = Self(reqwest::StatusCode::TEMPORARY_REDIRECT);
157 pub const PERMANENT_REDIRECT: Self = Self(reqwest::StatusCode::PERMANENT_REDIRECT);
158 pub const BAD_REQUEST: Self = Self(reqwest::StatusCode::BAD_REQUEST);
159 pub const UNAUTHORIZED: Self = Self(reqwest::StatusCode::UNAUTHORIZED);
160 pub const PAYMENT_REQUIRED: Self = Self(reqwest::StatusCode::PAYMENT_REQUIRED);
161 pub const FORBIDDEN: Self = Self(reqwest::StatusCode::FORBIDDEN);
162 pub const NOT_FOUND: Self = Self(reqwest::StatusCode::NOT_FOUND);
163 pub const METHOD_NOT_ALLOWED: Self = Self(reqwest::StatusCode::METHOD_NOT_ALLOWED);
164 pub const NOT_ACCEPTABLE: Self = Self(reqwest::StatusCode::NOT_ACCEPTABLE);
165 pub const PROXY_AUTHENTICATION_REQUIRED: Self =
166 Self(reqwest::StatusCode::PROXY_AUTHENTICATION_REQUIRED);
167 pub const REQUEST_TIMEOUT: Self = Self(reqwest::StatusCode::REQUEST_TIMEOUT);
168 pub const CONFLICT: Self = Self(reqwest::StatusCode::CONFLICT);
169 pub const GONE: Self = Self(reqwest::StatusCode::GONE);
170 pub const LENGTH_REQUIRED: Self = Self(reqwest::StatusCode::LENGTH_REQUIRED);
171 pub const PRECONDITION_FAILED: Self = Self(reqwest::StatusCode::PRECONDITION_FAILED);
172 pub const PAYLOAD_TOO_LARGE: Self = Self(reqwest::StatusCode::PAYLOAD_TOO_LARGE);
173 pub const URI_TOO_LONG: Self = Self(reqwest::StatusCode::URI_TOO_LONG);
174 pub const UNSUPPORTED_MEDIA_TYPE: Self = Self(reqwest::StatusCode::UNSUPPORTED_MEDIA_TYPE);
175 pub const RANGE_NOT_SATISFIABLE: Self = Self(reqwest::StatusCode::RANGE_NOT_SATISFIABLE);
176 pub const EXPECTATION_FAILED: Self = Self(reqwest::StatusCode::EXPECTATION_FAILED);
177 pub const IM_A_TEAPOT: Self = Self(reqwest::StatusCode::IM_A_TEAPOT);
178 pub const MISDIRECTED_REQUEST: Self = Self(reqwest::StatusCode::MISDIRECTED_REQUEST);
179 pub const UNPROCESSABLE_ENTITY: Self = Self(reqwest::StatusCode::UNPROCESSABLE_ENTITY);
180 pub const LOCKED: Self = Self(reqwest::StatusCode::LOCKED);
181 pub const FAILED_DEPENDENCY: Self = Self(reqwest::StatusCode::FAILED_DEPENDENCY);
182 pub const UPGRADE_REQUIRED: Self = Self(reqwest::StatusCode::UPGRADE_REQUIRED);
183 pub const PRECONDITION_REQUIRED: Self = Self(reqwest::StatusCode::PRECONDITION_REQUIRED);
184 pub const TOO_MANY_REQUESTS: Self = Self(reqwest::StatusCode::TOO_MANY_REQUESTS);
185 pub const REQUEST_HEADER_FIELDS_TOO_LARGE: Self =
186 Self(reqwest::StatusCode::REQUEST_HEADER_FIELDS_TOO_LARGE);
187 pub const UNAVAILABLE_FOR_LEGAL_REASONS: Self =
188 Self(reqwest::StatusCode::UNAVAILABLE_FOR_LEGAL_REASONS);
189 pub const INTERNAL_SERVER_ERROR: Self = Self(reqwest::StatusCode::INTERNAL_SERVER_ERROR);
190 pub const NOT_IMPLEMENTED: Self = Self(reqwest::StatusCode::NOT_IMPLEMENTED);
191 pub const BAD_GATEWAY: Self = Self(reqwest::StatusCode::BAD_GATEWAY);
192 pub const SERVICE_UNAVAILABLE: Self = Self(reqwest::StatusCode::SERVICE_UNAVAILABLE);
193 pub const GATEWAY_TIMEOUT: Self = Self(reqwest::StatusCode::GATEWAY_TIMEOUT);
194 pub const HTTP_VERSION_NOT_SUPPORTED: Self =
195 Self(reqwest::StatusCode::HTTP_VERSION_NOT_SUPPORTED);
196 pub const VARIANT_ALSO_NEGOTIATES: Self = Self(reqwest::StatusCode::VARIANT_ALSO_NEGOTIATES);
197 pub const INSUFFICIENT_STORAGE: Self = Self(reqwest::StatusCode::INSUFFICIENT_STORAGE);
198 pub const LOOP_DETECTED: Self = Self(reqwest::StatusCode::LOOP_DETECTED);
199 pub const NOT_EXTENDED: Self = Self(reqwest::StatusCode::NOT_EXTENDED);
200 pub const NETWORK_AUTHENTICATION_REQUIRED: Self =
201 Self(reqwest::StatusCode::NETWORK_AUTHENTICATION_REQUIRED);
202}
203
204#[cfg(test)]
205mod test {
206 use super::*;
207 use vbs::{version::StaticVersion, BinarySerializer, Serializer};
208
209 type SerializerV01 = Serializer<StaticVersion<0, 1>>;
210 #[test]
211 fn test_status_code() {
212 for code in 100u16.. {
213 let Ok(status) = StatusCode::try_from(code) else {
215 break;
216 };
217 if let Ok(tide_status) = tide::StatusCode::try_from(code) {
219 assert_eq!(tide_status, tide::StatusCode::try_from(status).unwrap());
220 }
221 assert_eq!(
222 reqwest::StatusCode::from_u16(code).unwrap(),
223 reqwest::StatusCode::from(status)
224 );
225 assert_eq!(code, u16::from(status));
226
227 assert_eq!(
229 status,
230 SerializerV01::deserialize::<StatusCode>(
231 &SerializerV01::serialize(&status).unwrap()
232 )
233 .unwrap()
234 );
235
236 let json = serde_json::to_string(&status).unwrap();
238 assert_eq!(status, serde_json::from_str::<StatusCode>(&json).unwrap());
239 assert_eq!(json, code.to_string());
240 if let Ok(tide_status) = tide::StatusCode::try_from(status) {
241 assert_eq!(json, serde_json::to_string(&tide_status).unwrap());
242 }
243
244 assert_eq!(status.to_string(), code.to_string());
246 if let Ok(tide_status) = tide::StatusCode::try_from(status) {
247 assert_eq!(status.to_string(), tide_status.to_string());
248 }
249
250 if let Ok(tide_status) = tide::StatusCode::try_from(status) {
252 assert_eq!(status, tide_status);
253 }
254 assert_eq!(status, reqwest::StatusCode::from(status));
255 }
256
257 for code in 100u16.. {
260 let Ok(status) = tide::StatusCode::try_from(code) else {
261 break;
262 };
263 assert_eq!(
264 StatusCode::try_from(code).unwrap(),
265 StatusCode::from(status)
266 );
267 }
268
269 for code in 100u16.. {
272 let Ok(status) = reqwest::StatusCode::from_u16(code) else {
273 break;
274 };
275 assert_eq!(
276 StatusCode::try_from(code).unwrap(),
277 StatusCode::from(status)
278 );
279 }
280 }
281}