Skip to main content

typespec/http/
status_code.rs

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