http_types/
status_code.rs

1use serde::de::{Error as DeError, Unexpected, Visitor};
2use serde::{Deserialize, Deserializer, Serialize, Serializer};
3use std::fmt::{self, Display};
4
5/// HTTP response status codes.
6///
7/// As defined by [rfc7231 section 6](https://tools.ietf.org/html/rfc7231#section-6).
8/// [Read more](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status)
9#[repr(u16)]
10#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
11pub enum StatusCode {
12    /// 100 Continue
13    ///
14    /// This interim response indicates that everything so far is OK and that
15    /// the client should continue the request, or ignore the response if
16    /// the request is already finished.
17    Continue = 100,
18
19    /// 101 Switching Protocols
20    ///
21    /// This code is sent in response to an Upgrade request header from the
22    /// client, and indicates the protocol the server is switching to.
23    SwitchingProtocols = 101,
24
25    /// 103 Early Hints
26    ///
27    /// This status code is primarily intended to be used with the Link header,
28    /// letting the user agent start preloading resources while the server
29    /// prepares a response.
30    EarlyHints = 103,
31
32    /// 200 Ok
33    ///
34    /// The request has succeeded
35    Ok = 200,
36
37    /// 201 Created
38    ///
39    /// The request has succeeded and a new resource has been created as a
40    /// result. This is typically the response sent after POST requests, or
41    /// some PUT requests.
42    Created = 201,
43
44    /// 202 Accepted
45    ///
46    /// The request has been received but not yet acted upon. It is
47    /// noncommittal, since there is no way in HTTP to later send an
48    /// asynchronous response indicating the outcome of the request. It is
49    /// intended for cases where another process or server handles the request,
50    /// or for batch processing.
51    Accepted = 202,
52
53    /// 203 Non Authoritative Information
54    ///
55    /// This response code means the returned meta-information is not exactly
56    /// the same as is available from the origin server, but is collected
57    /// from a local or a third-party copy. This is mostly used for mirrors
58    /// or backups of another resource. Except for that specific case, the
59    /// "200 OK" response is preferred to this status.
60    NonAuthoritativeInformation = 203,
61
62    /// 204 No Content
63    ///
64    /// There is no content to send for this request, but the headers may be
65    /// useful. The user-agent may update its cached headers for this
66    /// resource with the new ones.
67    NoContent = 204,
68
69    /// 205 Reset Content
70    ///
71    /// Tells the user-agent to reset the document which sent this request.
72    ResetContent = 205,
73
74    /// 206 Partial Content
75    ///
76    /// This response code is used when the Range header is sent from the client
77    /// to request only part of a resource.
78    PartialContent = 206,
79
80    /// 207 Multi-Status
81    ///
82    /// A Multi-Status response conveys information about
83    /// multiple resources in situations where multiple
84    /// status codes might be appropriate.
85    MultiStatus = 207,
86
87    /// 226 Im Used
88    ///
89    /// The server has fulfilled a GET request for the resource, and the
90    /// response is a representation of the result of one or more
91    /// instance-manipulations applied to the current instance.
92    ImUsed = 226,
93
94    /// 300 Multiple Choice
95    ///
96    /// The request has more than one possible response. The user-agent or user
97    /// should choose one of them. (There is no standardized way of choosing
98    /// one of the responses, but HTML links to the possibilities are
99    /// recommended so the user can pick.)
100    MultipleChoice = 300,
101
102    /// 301 Moved Permanently
103    ///
104    /// The URL of the requested resource has been changed permanently. The new
105    /// URL is given in the response.
106    MovedPermanently = 301,
107
108    /// 302 Found
109    ///
110    /// This response code means that the URI of requested resource has been
111    /// changed temporarily. Further changes in the URI might be made in the
112    /// future. Therefore, this same URI should be used by the client in
113    /// future requests.
114    Found = 302,
115
116    /// 303 See Other
117    ///
118    /// The server sent this response to direct the client to get the requested
119    /// resource at another URI with a GET request.
120    SeeOther = 303,
121
122    /// 304 Not Modified
123    ///
124    /// This is used for caching purposes. It tells the client that the response
125    /// has not been modified, so the client can continue to use the same
126    /// cached version of the response.
127    NotModified = 304,
128
129    /// 307 Temporary Redirect
130    ///
131    /// The server sends this response to direct the client to get the requested
132    /// resource at another URI with same method that was used in the prior
133    /// request. This has the same semantics as the 302 Found HTTP response
134    /// code, with the exception that the user agent must not change the
135    /// HTTP method used: If a POST was used in the first request, a POST must
136    /// be used in the second request.
137    TemporaryRedirect = 307,
138
139    /// 308 Permanent Redirect
140    ///
141    /// This means that the resource is now permanently located at another URI,
142    /// specified by the Location: HTTP Response header. This has the same
143    /// semantics as the 301 Moved Permanently HTTP response code, with the
144    /// exception that the user agent must not change the HTTP method
145    /// used: If a POST was used in the first request, a POST must be used in
146    /// the second request.
147    PermanentRedirect = 308,
148
149    /// 400 Bad Request
150    ///
151    /// The server could not understand the request due to invalid syntax.
152    BadRequest = 400,
153
154    /// 401 Unauthorized
155    ///
156    /// Although the HTTP standard specifies "unauthorized", semantically this
157    /// response means "unauthenticated". That is, the client must
158    /// authenticate itself to get the requested response.
159    Unauthorized = 401,
160
161    /// 402 Payment Required
162    ///
163    /// This response code is reserved for future use. The initial aim for
164    /// creating this code was using it for digital payment systems, however
165    /// this status code is used very rarely and no standard convention
166    /// exists.
167    PaymentRequired = 402,
168
169    /// 403 Forbidden
170    ///
171    /// The client does not have access rights to the content; that is, it is
172    /// unauthorized, so the server is refusing to give the requested
173    /// resource. Unlike 401, the client's identity is known to the server.
174    Forbidden = 403,
175
176    /// 404 Not Found
177    ///
178    /// The server can not find requested resource. In the browser, this means
179    /// the URL is not recognized. In an API, this can also mean that the
180    /// endpoint is valid but the resource itself does not exist. Servers
181    /// may also send this response instead of 403 to hide the existence of
182    /// a resource from an unauthorized client. This response code is probably
183    /// the most famous one due to its frequent occurrence on the web.
184    NotFound = 404,
185
186    /// 405 Method Not Allowed
187    ///
188    /// The request method is known by the server but has been disabled and
189    /// cannot be used. For example, an API may forbid DELETE-ing a
190    /// resource. The two mandatory methods, GET and HEAD, must never be
191    /// disabled and should not return this error code.
192    MethodNotAllowed = 405,
193
194    /// 406 Not Acceptable
195    ///
196    /// This response is sent when the web server, after performing
197    /// server-driven content negotiation, doesn't find any content that
198    /// conforms to the criteria given by the user agent.
199    NotAcceptable = 406,
200
201    /// 407 Proxy Authentication Required
202    ///
203    /// This is similar to 401 but authentication is needed to be done by a
204    /// proxy.
205    ProxyAuthenticationRequired = 407,
206
207    /// 408 Request Timeout
208    ///
209    /// This response is sent on an idle connection by some servers, even
210    /// without any previous request by the client. It means that the server
211    /// would like to shut down this unused connection. This response is
212    /// used much more since some browsers, like Chrome, Firefox 27+,
213    /// or IE9, use HTTP pre-connection mechanisms to speed up surfing. Also
214    /// note that some servers merely shut down the connection without
215    /// sending this message.
216    RequestTimeout = 408,
217
218    /// 409 Conflict
219    ///
220    /// This response is sent when a request conflicts with the current state of
221    /// the server.
222    Conflict = 409,
223
224    /// 410 Gone
225    ///
226    /// This response is sent when the requested content has been permanently
227    /// deleted from server, with no forwarding address. Clients are
228    /// expected to remove their caches and links to the resource. The HTTP
229    /// specification intends this status code to be used for "limited-time,
230    /// promotional services". APIs should not feel compelled to indicate
231    /// resources that have been deleted with this status code.
232    Gone = 410,
233
234    /// 411 Length Required
235    ///
236    /// Server rejected the request because the Content-Length header field is
237    /// not defined and the server requires it.
238    LengthRequired = 411,
239
240    /// 412 Precondition Failed
241    ///
242    /// The client has indicated preconditions in its headers which the server
243    /// does not meet.
244    PreconditionFailed = 412,
245
246    /// 413 Payload Too Large
247    ///
248    /// Request entity is larger than limits defined by server; the server might
249    /// close the connection or return an Retry-After header field.
250    PayloadTooLarge = 413,
251
252    /// 414 URI Too Long
253    ///
254    /// The URI requested by the client is longer than the server is willing to
255    /// interpret.
256    UriTooLong = 414,
257
258    /// 415 Unsupported Media Type
259    ///
260    /// The media format of the requested data is not supported by the server,
261    /// so the server is rejecting the request.
262    UnsupportedMediaType = 415,
263
264    /// 416 Requested Range Not Satisfiable
265    ///
266    /// The range specified by the Range header field in the request can't be
267    /// fulfilled; it's possible that the range is outside the size of the
268    /// target URI's data.
269    RequestedRangeNotSatisfiable = 416,
270
271    /// 417 Expectation Failed
272    ///
273    /// This response code means the expectation indicated by the Expect request
274    /// header field can't be met by the server.
275    ExpectationFailed = 417,
276    ///
277    /// 418 I'm a teapot
278    ///
279    /// The server refuses the attempt to brew coffee with a teapot.
280    ImATeapot = 418,
281
282    /// 421 Misdirected Request
283    ///
284    /// The request was directed at a server that is not able to produce a
285    /// response. This can be sent by a server that is not configured to
286    /// produce responses for the combination of scheme and authority that
287    /// are included in the request URI.
288    MisdirectedRequest = 421,
289
290    /// 422 Unprocessable Entity
291    ///
292    /// The request was well-formed but was unable to be followed due to
293    /// semantic errors.
294    UnprocessableEntity = 422,
295
296    /// 423 Locked
297    ///
298    /// The resource that is being accessed is locked.
299    Locked = 423,
300
301    /// 424 Failed Dependency
302    ///
303    /// The request failed because it depended on another request and that
304    /// request failed (e.g., a PROPPATCH).
305    FailedDependency = 424,
306
307    /// 425 Too Early
308    ///
309    /// Indicates that the server is unwilling to risk processing a request that
310    /// might be replayed.
311    TooEarly = 425,
312
313    /// 426 Upgrade Required
314    ///
315    /// The server refuses to perform the request using the current protocol but
316    /// might be willing to do so after the client upgrades to a different
317    /// protocol. The server sends an Upgrade header in a 426 response to
318    /// indicate the required protocol(s).
319    UpgradeRequired = 426,
320
321    /// 428 Precondition Required
322    ///
323    /// The origin server requires the request to be conditional. This response
324    /// is intended to prevent the 'lost update' problem, where a client
325    /// GETs a resource's state, modifies it, and PUTs it back to the
326    /// server, when meanwhile a third party has modified the state on the
327    /// server, leading to a conflict.
328    PreconditionRequired = 428,
329
330    /// 429 Too Many Requests
331    ///
332    /// The user has sent too many requests in a given amount of time ("rate
333    /// limiting").
334    TooManyRequests = 429,
335
336    /// 431 Request Header Fields Too Large
337    ///
338    /// The server is unwilling to process the request because its header fields
339    /// are too large. The request may be resubmitted after reducing the
340    /// size of the request header fields.
341    RequestHeaderFieldsTooLarge = 431,
342
343    /// 451 Unavailable For Legal Reasons
344    ///
345    /// The user-agent requested a resource that cannot legally be provided,
346    /// such as a web page censored by a government.
347    UnavailableForLegalReasons = 451,
348
349    /// 500 Internal Server Error
350    ///
351    /// The server has encountered a situation it doesn't know how to handle.
352    InternalServerError = 500,
353
354    /// 501 Not Implemented
355    ///
356    /// The request method is not supported by the server and cannot be handled.
357    /// The only methods that servers are required to support (and therefore
358    /// that must not return this code) are GET and HEAD.
359    NotImplemented = 501,
360
361    /// 502 Bad Gateway
362    ///
363    /// This error response means that the server, while working as a gateway to
364    /// get a response needed to handle the request, got an invalid
365    /// response.
366    BadGateway = 502,
367
368    /// 503 Service Unavailable
369    ///
370    /// The server is not ready to handle the request. Common causes are a
371    /// server that is down for maintenance or that is overloaded. Note that
372    /// together with this response, a user-friendly page explaining the
373    /// problem should be sent. This responses should be used for temporary
374    /// conditions and the Retry-After: HTTP header should, if possible, contain
375    /// the estimated time before the recovery of the service. The webmaster
376    /// must also take care about the caching-related headers that are sent
377    /// along with this response, as these temporary condition responses
378    /// should usually not be cached.
379    ServiceUnavailable = 503,
380
381    /// 504 Gateway Timeout
382    ///
383    /// This error response is given when the server is acting as a gateway and
384    /// cannot get a response in time.
385    GatewayTimeout = 504,
386
387    /// 505 HTTP Version Not Supported
388    ///
389    /// The HTTP version used in the request is not supported by the server.
390    HttpVersionNotSupported = 505,
391
392    /// 506 Variant Also Negotiates
393    ///
394    /// The server has an internal configuration error: the chosen variant
395    /// resource is configured to engage in transparent content negotiation
396    /// itself, and is therefore not a proper end point in the negotiation
397    /// process.
398    VariantAlsoNegotiates = 506,
399
400    /// 507 Insufficient Storage
401    ///
402    /// The server is unable to store the representation needed to complete the
403    /// request.
404    InsufficientStorage = 507,
405
406    /// 508 Loop Detected
407    ///
408    /// The server detected an infinite loop while processing the request.
409    LoopDetected = 508,
410
411    /// 510 Not Extended
412    ///
413    /// Further extensions to the request are required for the server to fulfil
414    /// it.
415    NotExtended = 510,
416
417    /// 511 Network Authentication Required
418    ///
419    /// The 511 status code indicates that the client needs to authenticate to
420    /// gain network access.
421    NetworkAuthenticationRequired = 511,
422}
423
424impl StatusCode {
425    /// Returns `true` if the status code is `1xx` range.
426    ///
427    /// If this returns `true` it indicates that the request was received,
428    /// continuing process.
429    pub fn is_informational(&self) -> bool {
430        let num: u16 = (*self).into();
431        (100..200).contains(&num)
432    }
433
434    /// Returns `true` if the status code is the `2xx` range.
435    ///
436    /// If this returns `true` it indicates that the request was successfully
437    /// received, understood, and accepted.
438    pub fn is_success(&self) -> bool {
439        let num: u16 = (*self).into();
440        (200..300).contains(&num)
441    }
442
443    /// Returns `true` if the status code is the `3xx` range.
444    ///
445    /// If this returns `true` it indicates that further action needs to be
446    /// taken in order to complete the request.
447    pub fn is_redirection(&self) -> bool {
448        let num: u16 = (*self).into();
449        (300..400).contains(&num)
450    }
451
452    /// Returns `true` if the status code is the `4xx` range.
453    ///
454    /// If this returns `true` it indicates that the request contains bad syntax
455    /// or cannot be fulfilled.
456    pub fn is_client_error(&self) -> bool {
457        let num: u16 = (*self).into();
458        (400..500).contains(&num)
459    }
460
461    /// Returns `true` if the status code is the `5xx` range.
462    ///
463    /// If this returns `true` it indicates that the server failed to fulfill an
464    /// apparently valid request.
465    pub fn is_server_error(&self) -> bool {
466        let num: u16 = (*self).into();
467        (500..600).contains(&num)
468    }
469
470    /// The canonical reason for a given status code
471    pub fn canonical_reason(&self) -> &'static str {
472        match self {
473            StatusCode::Continue => "Continue",
474            StatusCode::SwitchingProtocols => "Switching Protocols",
475            StatusCode::EarlyHints => "Early Hints",
476            StatusCode::Ok => "OK",
477            StatusCode::Created => "Created",
478            StatusCode::Accepted => "Accepted",
479            StatusCode::NonAuthoritativeInformation => "Non Authoritative Information",
480            StatusCode::NoContent => "No Content",
481            StatusCode::ResetContent => "Reset Content",
482            StatusCode::PartialContent => "Partial Content",
483            StatusCode::MultiStatus => "Multi-Status",
484            StatusCode::ImUsed => "Im Used",
485            StatusCode::MultipleChoice => "Multiple Choice",
486            StatusCode::MovedPermanently => "Moved Permanently",
487            StatusCode::Found => "Found",
488            StatusCode::SeeOther => "See Other",
489            StatusCode::NotModified => "Modified",
490            StatusCode::TemporaryRedirect => "Temporary Redirect",
491            StatusCode::PermanentRedirect => "Permanent Redirect",
492            StatusCode::BadRequest => "Bad Request",
493            StatusCode::Unauthorized => "Unauthorized",
494            StatusCode::PaymentRequired => "Payment Required",
495            StatusCode::Forbidden => "Forbidden",
496            StatusCode::NotFound => "Not Found",
497            StatusCode::MethodNotAllowed => "Method Not Allowed",
498            StatusCode::NotAcceptable => "Not Acceptable",
499            StatusCode::ProxyAuthenticationRequired => "Proxy Authentication Required",
500            StatusCode::RequestTimeout => "Request Timeout",
501            StatusCode::Conflict => "Conflict",
502            StatusCode::Gone => "Gone",
503            StatusCode::LengthRequired => "Length Required",
504            StatusCode::PreconditionFailed => "Precondition Failed",
505            StatusCode::PayloadTooLarge => "Payload Too Large",
506            StatusCode::UriTooLong => "URI Too Long",
507            StatusCode::UnsupportedMediaType => "Unsupported Media Type",
508            StatusCode::RequestedRangeNotSatisfiable => "Requested Range Not Satisfiable",
509            StatusCode::ExpectationFailed => "Expectation Failed",
510            StatusCode::ImATeapot => "I'm a teapot",
511            StatusCode::MisdirectedRequest => "Misdirected Request",
512            StatusCode::UnprocessableEntity => "Unprocessable Entity",
513            StatusCode::Locked => "Locked",
514            StatusCode::FailedDependency => "Failed Dependency",
515            StatusCode::TooEarly => "Too Early",
516            StatusCode::UpgradeRequired => "Upgrade Required",
517            StatusCode::PreconditionRequired => "Precondition Required",
518            StatusCode::TooManyRequests => "Too Many Requests",
519            StatusCode::RequestHeaderFieldsTooLarge => "Request Header Fields Too Large",
520            StatusCode::UnavailableForLegalReasons => "Unavailable For Legal Reasons",
521            StatusCode::InternalServerError => "Internal Server Error",
522            StatusCode::NotImplemented => "Not Implemented",
523            StatusCode::BadGateway => "Bad Gateway",
524            StatusCode::ServiceUnavailable => "Service Unavailable",
525            StatusCode::GatewayTimeout => "Gateway Timeout",
526            StatusCode::HttpVersionNotSupported => "HTTP Version Not Supported",
527            StatusCode::VariantAlsoNegotiates => "Variant Also Negotiates",
528            StatusCode::InsufficientStorage => "Insufficient Storage",
529            StatusCode::LoopDetected => "Loop Detected",
530            StatusCode::NotExtended => "Not Extended",
531            StatusCode::NetworkAuthenticationRequired => "Network Authentication Required",
532        }
533    }
534}
535
536impl Serialize for StatusCode {
537    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
538    where
539        S: Serializer,
540    {
541        let value: u16 = *self as u16;
542        serializer.serialize_u16(value)
543    }
544}
545
546struct StatusCodeU16Visitor;
547
548impl<'de> Visitor<'de> for StatusCodeU16Visitor {
549    type Value = StatusCode;
550
551    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
552        write!(formatter, "a u16 representing the status code")
553    }
554
555    fn visit_i16<E>(self, v: i16) -> Result<Self::Value, E>
556    where
557        E: DeError,
558    {
559        self.visit_u16(v as u16)
560    }
561
562    fn visit_i32<E>(self, v: i32) -> Result<Self::Value, E>
563    where
564        E: DeError,
565    {
566        self.visit_u16(v as u16)
567    }
568
569    fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
570    where
571        E: DeError,
572    {
573        self.visit_u16(v as u16)
574    }
575
576    fn visit_u16<E>(self, v: u16) -> Result<Self::Value, E>
577    where
578        E: DeError,
579    {
580        use std::convert::TryFrom;
581        match StatusCode::try_from(v) {
582            Ok(status_code) => Ok(status_code),
583            Err(_) => Err(DeError::invalid_value(
584                Unexpected::Unsigned(v as u64),
585                &self,
586            )),
587        }
588    }
589
590    fn visit_u32<E>(self, v: u32) -> Result<Self::Value, E>
591    where
592        E: DeError,
593    {
594        self.visit_u16(v as u16)
595    }
596
597    fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
598    where
599        E: DeError,
600    {
601        self.visit_u16(v as u16)
602    }
603}
604
605impl<'de> Deserialize<'de> for StatusCode {
606    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
607    where
608        D: Deserializer<'de>,
609    {
610        deserializer.deserialize_any(StatusCodeU16Visitor)
611    }
612}
613
614impl From<StatusCode> for u16 {
615    fn from(code: StatusCode) -> u16 {
616        code as u16
617    }
618}
619
620impl std::convert::TryFrom<u16> for StatusCode {
621    type Error = crate::Error;
622
623    fn try_from(num: u16) -> Result<Self, Self::Error> {
624        match num {
625            100 => Ok(StatusCode::Continue),
626            101 => Ok(StatusCode::SwitchingProtocols),
627            103 => Ok(StatusCode::EarlyHints),
628            200 => Ok(StatusCode::Ok),
629            201 => Ok(StatusCode::Created),
630            202 => Ok(StatusCode::Accepted),
631            203 => Ok(StatusCode::NonAuthoritativeInformation),
632            204 => Ok(StatusCode::NoContent),
633            205 => Ok(StatusCode::ResetContent),
634            206 => Ok(StatusCode::PartialContent),
635            207 => Ok(StatusCode::MultiStatus),
636            226 => Ok(StatusCode::ImUsed),
637            300 => Ok(StatusCode::MultipleChoice),
638            301 => Ok(StatusCode::MovedPermanently),
639            302 => Ok(StatusCode::Found),
640            303 => Ok(StatusCode::SeeOther),
641            304 => Ok(StatusCode::NotModified),
642            307 => Ok(StatusCode::TemporaryRedirect),
643            308 => Ok(StatusCode::PermanentRedirect),
644            400 => Ok(StatusCode::BadRequest),
645            401 => Ok(StatusCode::Unauthorized),
646            402 => Ok(StatusCode::PaymentRequired),
647            403 => Ok(StatusCode::Forbidden),
648            404 => Ok(StatusCode::NotFound),
649            405 => Ok(StatusCode::MethodNotAllowed),
650            406 => Ok(StatusCode::NotAcceptable),
651            407 => Ok(StatusCode::ProxyAuthenticationRequired),
652            408 => Ok(StatusCode::RequestTimeout),
653            409 => Ok(StatusCode::Conflict),
654            410 => Ok(StatusCode::Gone),
655            411 => Ok(StatusCode::LengthRequired),
656            412 => Ok(StatusCode::PreconditionFailed),
657            413 => Ok(StatusCode::PayloadTooLarge),
658            414 => Ok(StatusCode::UriTooLong),
659            415 => Ok(StatusCode::UnsupportedMediaType),
660            416 => Ok(StatusCode::RequestedRangeNotSatisfiable),
661            417 => Ok(StatusCode::ExpectationFailed),
662            418 => Ok(StatusCode::ImATeapot),
663            421 => Ok(StatusCode::MisdirectedRequest),
664            422 => Ok(StatusCode::UnprocessableEntity),
665            423 => Ok(StatusCode::Locked),
666            424 => Ok(StatusCode::FailedDependency),
667            425 => Ok(StatusCode::TooEarly),
668            426 => Ok(StatusCode::UpgradeRequired),
669            428 => Ok(StatusCode::PreconditionRequired),
670            429 => Ok(StatusCode::TooManyRequests),
671            431 => Ok(StatusCode::RequestHeaderFieldsTooLarge),
672            451 => Ok(StatusCode::UnavailableForLegalReasons),
673            500 => Ok(StatusCode::InternalServerError),
674            501 => Ok(StatusCode::NotImplemented),
675            502 => Ok(StatusCode::BadGateway),
676            503 => Ok(StatusCode::ServiceUnavailable),
677            504 => Ok(StatusCode::GatewayTimeout),
678            505 => Ok(StatusCode::HttpVersionNotSupported),
679            506 => Ok(StatusCode::VariantAlsoNegotiates),
680            507 => Ok(StatusCode::InsufficientStorage),
681            508 => Ok(StatusCode::LoopDetected),
682            510 => Ok(StatusCode::NotExtended),
683            511 => Ok(StatusCode::NetworkAuthenticationRequired),
684            _ => crate::bail!("Invalid status code"),
685        }
686    }
687}
688
689impl PartialEq<StatusCode> for u16 {
690    fn eq(&self, other: &StatusCode) -> bool {
691        *self == *other as u16
692    }
693}
694
695impl PartialEq<u16> for StatusCode {
696    fn eq(&self, other: &u16) -> bool {
697        *self as u16 == *other
698    }
699}
700
701impl Display for StatusCode {
702    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
703        write!(f, "{}", *self as u16)
704    }
705}
706
707#[cfg(test)]
708mod test {
709    use super::StatusCode;
710    #[test]
711    fn serde_as_u16() -> Result<(), serde_json::Error> {
712        let status_code: StatusCode = serde_json::from_str("202")?;
713        assert_eq!(StatusCode::Accepted, status_code);
714        assert_eq!(
715            Some(202),
716            serde_json::to_value(&StatusCode::Accepted)?.as_u64()
717        );
718        Ok(())
719    }
720}