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