Skip to main content

trillium_http/
status.rs

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