Skip to main content

rama_http_types/
status.rs

1//! Forked from the `http` crate — vendored so rama owns its HTTP leaf types.
2//! See `docs/thirdparty/fork/README.md`.
3//!
4//! HTTP status codes
5//!
6//! This module contains HTTP-status code related structs and errors. The main
7//! type in this module is `StatusCode` which is not intended to be used through
8//! this module but rather the `rama_http_types::StatusCode` type.
9//!
10//! # Examples
11//!
12//! ```
13//! use rama_http_types::StatusCode;
14//!
15//! assert_eq!(StatusCode::from_u16(200).unwrap(), StatusCode::OK);
16//! assert_eq!(StatusCode::NOT_FOUND, 404);
17//! assert!(StatusCode::OK.is_success());
18//! ```
19
20// Vendored verbatim from `http`; keep upstream's style rather than rama's.
21#![allow(
22    unreachable_pub,
23    clippy::use_self,
24    clippy::needless_lifetimes,
25    clippy::enum_glob_use,
26    clippy::collapsible_if,
27    clippy::assertions_on_result_states
28)]
29
30use std::convert::TryFrom;
31use std::error::Error;
32use std::fmt;
33use std::num::NonZeroU16;
34use std::str::FromStr;
35
36/// An HTTP status code (`status-code` in RFC 9110 et al.).
37///
38/// Constants are provided for known status codes, including those in the IANA
39/// [HTTP Status Code Registry](
40/// https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml).
41///
42/// Status code values in the range 100-999 (inclusive) are supported by this
43/// type. Values in the range 100-599 are semantically classified by the most
44/// significant digit. See [`StatusCode::is_success`], etc. Values above 599
45/// are unclassified but allowed for legacy compatibility, though their use is
46/// discouraged. Applications may interpret such values as protocol errors.
47///
48/// # Examples
49///
50/// ```
51/// use rama_http_types::StatusCode;
52///
53/// assert_eq!(StatusCode::from_u16(200).unwrap(), StatusCode::OK);
54/// assert_eq!(StatusCode::NOT_FOUND.as_u16(), 404);
55/// assert!(StatusCode::OK.is_success());
56/// ```
57#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
58pub struct StatusCode(NonZeroU16);
59
60/// A possible error value when converting a `StatusCode` from a `u16` or `&str`.
61///
62/// This error indicates that the supplied input was not a valid number, was less
63/// than 100, or was greater than 999.
64pub struct InvalidStatusCode {
65    _priv: (),
66}
67
68impl StatusCode {
69    /// Converts a u16 to a status code.
70    ///
71    /// The function validates the correctness of the supplied u16. It must be
72    /// greater or equal to 100 and less than 1000.
73    ///
74    /// # Example
75    ///
76    /// ```
77    /// use rama_http_types::StatusCode;
78    ///
79    /// let ok = StatusCode::from_u16(200).unwrap();
80    /// assert_eq!(ok, StatusCode::OK);
81    ///
82    /// let err = StatusCode::from_u16(99);
83    /// assert!(err.is_err());
84    /// ```
85    #[inline]
86    pub const fn from_u16(src: u16) -> Result<StatusCode, InvalidStatusCode> {
87        if let 100..=999 = src {
88            if let Some(code) = NonZeroU16::new(src) {
89                return Ok(StatusCode(code));
90            }
91        }
92        Err(InvalidStatusCode::new())
93    }
94
95    /// Converts a `&[u8]` to a status code.
96    pub fn from_bytes(src: &[u8]) -> Result<StatusCode, InvalidStatusCode> {
97        if src.len() != 3 {
98            return Err(InvalidStatusCode::new());
99        }
100
101        let a = src[0].wrapping_sub(b'0') as u16;
102        let b = src[1].wrapping_sub(b'0') as u16;
103        let c = src[2].wrapping_sub(b'0') as u16;
104
105        if a == 0 || a > 9 || b > 9 || c > 9 {
106            return Err(InvalidStatusCode::new());
107        }
108
109        let status = (a * 100) + (b * 10) + c;
110        NonZeroU16::new(status)
111            .map(StatusCode)
112            .ok_or_else(InvalidStatusCode::new)
113    }
114
115    /// Returns the `u16` corresponding to this `StatusCode`.
116    ///
117    /// # Note
118    ///
119    /// This is the same as the `From<StatusCode>` implementation, but
120    /// included as an inherent method because that implementation doesn't
121    /// appear in rustdocs, as well as a way to force the type instead of
122    /// relying on inference.
123    ///
124    /// # Example
125    ///
126    /// ```
127    /// let status = rama_http_types::StatusCode::OK;
128    /// assert_eq!(status.as_u16(), 200);
129    /// ```
130    #[inline]
131    pub const fn as_u16(&self) -> u16 {
132        self.0.get()
133    }
134
135    /// Returns a &str representation of the `StatusCode`
136    ///
137    /// The return value only includes a numerical representation of the
138    /// status code. The canonical reason is not included.
139    ///
140    /// # Example
141    ///
142    /// ```
143    /// let status = rama_http_types::StatusCode::OK;
144    /// assert_eq!(status.as_str(), "200");
145    /// ```
146    #[inline]
147    pub fn as_str(&self) -> &str {
148        let offset = (self.0.get() - 100) as usize;
149        let offset = offset * 3;
150
151        // Invariant: self has checked range [100, 999] and CODE_DIGITS is
152        // ASCII-only, of length 900 * 3 = 2700 bytes
153
154        #[cfg(debug_assertions)]
155        {
156            &CODE_DIGITS[offset..offset + 3]
157        }
158
159        #[cfg(not(debug_assertions))]
160        unsafe {
161            CODE_DIGITS.get_unchecked(offset..offset + 3)
162        }
163    }
164
165    /// Get the standardised `reason-phrase` for this status code.
166    ///
167    /// This is mostly here for servers writing responses, but could potentially have application
168    /// at other times.
169    ///
170    /// The reason phrase is defined as being exclusively for human readers. You should avoid
171    /// deriving any meaning from it at all costs.
172    ///
173    /// Bear in mind also that in HTTP/2.0 and HTTP/3.0 the reason phrase is abolished from
174    /// transmission, and so this canonical reason phrase really is the only reason phrase you’ll
175    /// find.
176    ///
177    /// # Example
178    ///
179    /// ```
180    /// let status = rama_http_types::StatusCode::OK;
181    /// assert_eq!(status.canonical_reason(), Some("OK"));
182    /// ```
183    pub fn canonical_reason(&self) -> Option<&'static str> {
184        canonical_reason(self.0.get())
185    }
186
187    /// Check if status is within 100-199.
188    #[inline]
189    pub fn is_informational(&self) -> bool {
190        (100..200).contains(&self.0.get())
191    }
192
193    /// Check if status is within 200-299.
194    #[inline]
195    pub fn is_success(&self) -> bool {
196        (200..300).contains(&self.0.get())
197    }
198
199    /// Check if status is within 300-399.
200    #[inline]
201    pub fn is_redirection(&self) -> bool {
202        (300..400).contains(&self.0.get())
203    }
204
205    /// Check if status is within 400-499.
206    #[inline]
207    pub fn is_client_error(&self) -> bool {
208        (400..500).contains(&self.0.get())
209    }
210
211    /// Check if status is within 500-599.
212    #[inline]
213    pub fn is_server_error(&self) -> bool {
214        (500..600).contains(&self.0.get())
215    }
216}
217
218impl fmt::Debug for StatusCode {
219    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
220        fmt::Debug::fmt(&self.0, f)
221    }
222}
223
224/// Formats the status code, *including* the canonical reason.
225///
226/// # Example
227///
228/// ```
229/// # use rama_http_types::StatusCode;
230/// assert_eq!(format!("{}", StatusCode::OK), "200 OK");
231/// ```
232impl fmt::Display for StatusCode {
233    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
234        write!(
235            f,
236            "{} {}",
237            u16::from(*self),
238            self.canonical_reason().unwrap_or("<unknown status code>")
239        )
240    }
241}
242
243impl Default for StatusCode {
244    #[inline]
245    fn default() -> StatusCode {
246        StatusCode::OK
247    }
248}
249
250impl PartialEq<u16> for StatusCode {
251    #[inline]
252    fn eq(&self, other: &u16) -> bool {
253        self.as_u16() == *other
254    }
255}
256
257impl PartialEq<StatusCode> for u16 {
258    #[inline]
259    fn eq(&self, other: &StatusCode) -> bool {
260        *self == other.as_u16()
261    }
262}
263
264impl From<StatusCode> for u16 {
265    #[inline]
266    fn from(status: StatusCode) -> u16 {
267        status.0.get()
268    }
269}
270
271impl FromStr for StatusCode {
272    type Err = InvalidStatusCode;
273
274    fn from_str(s: &str) -> Result<StatusCode, InvalidStatusCode> {
275        StatusCode::from_bytes(s.as_ref())
276    }
277}
278
279impl From<&StatusCode> for StatusCode {
280    #[inline]
281    fn from(t: &StatusCode) -> Self {
282        t.to_owned()
283    }
284}
285
286impl TryFrom<&[u8]> for StatusCode {
287    type Error = InvalidStatusCode;
288
289    #[inline]
290    fn try_from(t: &[u8]) -> Result<Self, Self::Error> {
291        StatusCode::from_bytes(t)
292    }
293}
294
295impl TryFrom<&str> for StatusCode {
296    type Error = InvalidStatusCode;
297
298    #[inline]
299    fn try_from(t: &str) -> Result<Self, Self::Error> {
300        t.parse()
301    }
302}
303
304impl TryFrom<u16> for StatusCode {
305    type Error = InvalidStatusCode;
306
307    #[inline]
308    fn try_from(t: u16) -> Result<Self, Self::Error> {
309        StatusCode::from_u16(t)
310    }
311}
312
313macro_rules! status_codes {
314    (
315        $(
316            $(#[$docs:meta])*
317            ($num:expr, $konst:ident, $phrase:expr);
318        )+
319    ) => {
320        impl StatusCode {
321        $(
322            $(#[$docs])*
323            pub const $konst: StatusCode = StatusCode(unsafe { NonZeroU16::new_unchecked($num) });
324        )+
325
326        }
327
328        fn canonical_reason(num: u16) -> Option<&'static str> {
329            match num {
330                $(
331                $num => Some($phrase),
332                )+
333                _ => None
334            }
335        }
336    }
337}
338
339status_codes! {
340    /// 100 Continue
341    /// [[RFC9110, Section 15.2.1](https://datatracker.ietf.org/doc/html/rfc9110#section-15.2.1)]
342    (100, CONTINUE, "Continue");
343    /// 101 Switching Protocols
344    /// [[RFC9110, Section 15.2.2](https://datatracker.ietf.org/doc/html/rfc9110#section-15.2.2)]
345    (101, SWITCHING_PROTOCOLS, "Switching Protocols");
346    /// 102 Processing
347    /// [[RFC2518, Section 10.1](https://datatracker.ietf.org/doc/html/rfc2518#section-10.1)]
348    (102, PROCESSING, "Processing");
349    /// 103 Early Hints
350    /// [[RFC8297, Section 2](https://datatracker.ietf.org/doc/html/rfc8297#section-2)]
351    (103, EARLY_HINTS, "Early Hints");
352
353    /// 200 OK
354    /// [[RFC9110, Section 15.3.1](https://datatracker.ietf.org/doc/html/rfc9110#section-15.3.1)]
355    (200, OK, "OK");
356    /// 201 Created
357    /// [[RFC9110, Section 15.3.2](https://datatracker.ietf.org/doc/html/rfc9110#section-15.3.2)]
358    (201, CREATED, "Created");
359    /// 202 Accepted
360    /// [[RFC9110, Section 15.3.3](https://datatracker.ietf.org/doc/html/rfc9110#section-15.3.3)]
361    (202, ACCEPTED, "Accepted");
362    /// 203 Non-Authoritative Information
363    /// [[RFC9110, Section 15.3.4](https://datatracker.ietf.org/doc/html/rfc9110#section-15.3.4)]
364    (203, NON_AUTHORITATIVE_INFORMATION, "Non Authoritative Information");
365    /// 204 No Content
366    /// [[RFC9110, Section 15.3.5](https://datatracker.ietf.org/doc/html/rfc9110#section-15.3.5)]
367    (204, NO_CONTENT, "No Content");
368    /// 205 Reset Content
369    /// [[RFC9110, Section 15.3.6](https://datatracker.ietf.org/doc/html/rfc9110#section-15.3.6)]
370    (205, RESET_CONTENT, "Reset Content");
371    /// 206 Partial Content
372    /// [[RFC9110, Section 15.3.7](https://datatracker.ietf.org/doc/html/rfc9110#section-15.3.7)]
373    (206, PARTIAL_CONTENT, "Partial Content");
374    /// 207 Multi-Status
375    /// [[RFC4918, Section 11.1](https://datatracker.ietf.org/doc/html/rfc4918#section-11.1)]
376    (207, MULTI_STATUS, "Multi-Status");
377    /// 208 Already Reported
378    /// [[RFC5842, Section 7.1](https://datatracker.ietf.org/doc/html/rfc5842#section-7.1)]
379    (208, ALREADY_REPORTED, "Already Reported");
380
381    /// 226 IM Used
382    /// [[RFC3229, Section 10.4.1](https://datatracker.ietf.org/doc/html/rfc3229#section-10.4.1)]
383    (226, IM_USED, "IM Used");
384
385    /// 300 Multiple Choices
386    /// [[RFC9110, Section 15.4.1](https://datatracker.ietf.org/doc/html/rfc9110#section-15.4.1)]
387    (300, MULTIPLE_CHOICES, "Multiple Choices");
388    /// 301 Moved Permanently
389    /// [[RFC9110, Section 15.4.2](https://datatracker.ietf.org/doc/html/rfc9110#section-15.4.2)]
390    (301, MOVED_PERMANENTLY, "Moved Permanently");
391    /// 302 Found
392    /// [[RFC9110, Section 15.4.3](https://datatracker.ietf.org/doc/html/rfc9110#section-15.4.3)]
393    (302, FOUND, "Found");
394    /// 303 See Other
395    /// [[RFC9110, Section 15.4.4](https://datatracker.ietf.org/doc/html/rfc9110#section-15.4.4)]
396    (303, SEE_OTHER, "See Other");
397    /// 304 Not Modified
398    /// [[RFC9110, Section 15.4.5](https://datatracker.ietf.org/doc/html/rfc9110#section-15.4.5)]
399    (304, NOT_MODIFIED, "Not Modified");
400    /// 305 Use Proxy
401    /// [[RFC9110, Section 15.4.6](https://datatracker.ietf.org/doc/html/rfc9110#section-15.4.6)]
402    (305, USE_PROXY, "Use Proxy");
403    /// 307 Temporary Redirect
404    /// [[RFC9110, Section 15.4.7](https://datatracker.ietf.org/doc/html/rfc9110#section-15.4.7)]
405    (307, TEMPORARY_REDIRECT, "Temporary Redirect");
406    /// 308 Permanent Redirect
407    /// [[RFC9110, Section 15.4.8](https://datatracker.ietf.org/doc/html/rfc9110#section-15.4.8)]
408    (308, PERMANENT_REDIRECT, "Permanent Redirect");
409
410    /// 400 Bad Request
411    /// [[RFC9110, Section 15.5.1](https://datatracker.ietf.org/doc/html/rfc9110#section-15.5.1)]
412    (400, BAD_REQUEST, "Bad Request");
413    /// 401 Unauthorized
414    /// [[RFC9110, Section 15.5.2](https://datatracker.ietf.org/doc/html/rfc9110#section-15.5.2)]
415    (401, UNAUTHORIZED, "Unauthorized");
416    /// 402 Payment Required
417    /// [[RFC9110, Section 15.5.3](https://datatracker.ietf.org/doc/html/rfc9110#section-15.5.3)]
418    (402, PAYMENT_REQUIRED, "Payment Required");
419    /// 403 Forbidden
420    /// [[RFC9110, Section 15.5.4](https://datatracker.ietf.org/doc/html/rfc9110#section-15.5.4)]
421    (403, FORBIDDEN, "Forbidden");
422    /// 404 Not Found
423    /// [[RFC9110, Section 15.5.5](https://datatracker.ietf.org/doc/html/rfc9110#section-15.5.5)]
424    (404, NOT_FOUND, "Not Found");
425    /// 405 Method Not Allowed
426    /// [[RFC9110, Section 15.5.6](https://datatracker.ietf.org/doc/html/rfc9110#section-15.5.6)]
427    (405, METHOD_NOT_ALLOWED, "Method Not Allowed");
428    /// 406 Not Acceptable
429    /// [[RFC9110, Section 15.5.7](https://datatracker.ietf.org/doc/html/rfc9110#section-15.5.7)]
430    (406, NOT_ACCEPTABLE, "Not Acceptable");
431    /// 407 Proxy Authentication Required
432    /// [[RFC9110, Section 15.5.8](https://datatracker.ietf.org/doc/html/rfc9110#section-15.5.8)]
433    (407, PROXY_AUTHENTICATION_REQUIRED, "Proxy Authentication Required");
434    /// 408 Request Timeout
435    /// [[RFC9110, Section 15.5.9](https://datatracker.ietf.org/doc/html/rfc9110#section-15.5.9)]
436    (408, REQUEST_TIMEOUT, "Request Timeout");
437    /// 409 Conflict
438    /// [[RFC9110, Section 15.5.10](https://datatracker.ietf.org/doc/html/rfc9110#section-15.5.10)]
439    (409, CONFLICT, "Conflict");
440    /// 410 Gone
441    /// [[RFC9110, Section 15.5.11](https://datatracker.ietf.org/doc/html/rfc9110#section-15.5.11)]
442    (410, GONE, "Gone");
443    /// 411 Length Required
444    /// [[RFC9110, Section 15.5.12](https://datatracker.ietf.org/doc/html/rfc9110#section-15.5.12)]
445    (411, LENGTH_REQUIRED, "Length Required");
446    /// 412 Precondition Failed
447    /// [[RFC9110, Section 15.5.13](https://datatracker.ietf.org/doc/html/rfc9110#section-15.5.13)]
448    (412, PRECONDITION_FAILED, "Precondition Failed");
449    /// 413 Payload Too Large
450    /// [[RFC9110, Section 15.5.14](https://datatracker.ietf.org/doc/html/rfc9110#section-15.5.14)]
451    (413, PAYLOAD_TOO_LARGE, "Payload Too Large");
452    /// 414 URI Too Long
453    /// [[RFC9110, Section 15.5.15](https://datatracker.ietf.org/doc/html/rfc9110#section-15.5.15)]
454    (414, URI_TOO_LONG, "URI Too Long");
455    /// 415 Unsupported Media Type
456    /// [[RFC9110, Section 15.5.16](https://datatracker.ietf.org/doc/html/rfc9110#section-15.5.16)]
457    (415, UNSUPPORTED_MEDIA_TYPE, "Unsupported Media Type");
458    /// 416 Range Not Satisfiable
459    /// [[RFC9110, Section 15.5.17](https://datatracker.ietf.org/doc/html/rfc9110#section-15.5.17)]
460    (416, RANGE_NOT_SATISFIABLE, "Range Not Satisfiable");
461    /// 417 Expectation Failed
462    /// [[RFC9110, Section 15.5.18](https://datatracker.ietf.org/doc/html/rfc9110#section-15.5.18)]
463    (417, EXPECTATION_FAILED, "Expectation Failed");
464    /// 418 I'm a teapot
465    /// [curiously not registered by IANA but [RFC2324, Section 2.3.2](https://datatracker.ietf.org/doc/html/rfc2324#section-2.3.2)]
466    (418, IM_A_TEAPOT, "I'm a teapot");
467
468    /// 421 Misdirected Request
469    /// [[RFC9110, Section 15.5.20](https://datatracker.ietf.org/doc/html/rfc9110#section-15.5.20)]
470    (421, MISDIRECTED_REQUEST, "Misdirected Request");
471    /// 422 Unprocessable Entity
472    /// [[RFC9110, Section 15.5.21](https://datatracker.ietf.org/doc/html/rfc9110#section-15.5.21)]
473    (422, UNPROCESSABLE_ENTITY, "Unprocessable Entity");
474    /// 423 Locked
475    /// [[RFC4918, Section 11.3](https://datatracker.ietf.org/doc/html/rfc4918#section-11.3)]
476    (423, LOCKED, "Locked");
477    /// 424 Failed Dependency
478    /// [[RFC4918, Section 11.4](https://tools.ietf.org/html/rfc4918#section-11.4)]
479    (424, FAILED_DEPENDENCY, "Failed Dependency");
480
481    /// 425 Too early
482    /// [[RFC8470, Section 5.2](https://httpwg.org/specs/rfc8470.html#status)]
483    (425, TOO_EARLY, "Too Early");
484
485    /// 426 Upgrade Required
486    /// [[RFC9110, Section 15.5.22](https://datatracker.ietf.org/doc/html/rfc9110#section-15.5.22)]
487    (426, UPGRADE_REQUIRED, "Upgrade Required");
488
489    /// 428 Precondition Required
490    /// [[RFC6585, Section 3](https://datatracker.ietf.org/doc/html/rfc6585#section-3)]
491    (428, PRECONDITION_REQUIRED, "Precondition Required");
492    /// 429 Too Many Requests
493    /// [[RFC6585, Section 4](https://datatracker.ietf.org/doc/html/rfc6585#section-4)]
494    (429, TOO_MANY_REQUESTS, "Too Many Requests");
495
496    /// 431 Request Header Fields Too Large
497    /// [[RFC6585, Section 5](https://datatracker.ietf.org/doc/html/rfc6585#section-5)]
498    (431, REQUEST_HEADER_FIELDS_TOO_LARGE, "Request Header Fields Too Large");
499
500    /// 451 Unavailable For Legal Reasons
501    /// [[RFC7725, Section 3](https://tools.ietf.org/html/rfc7725#section-3)]
502    (451, UNAVAILABLE_FOR_LEGAL_REASONS, "Unavailable For Legal Reasons");
503
504    /// 500 Internal Server Error
505    /// [[RFC9110, Section 15.6.1](https://datatracker.ietf.org/doc/html/rfc9110#section-15.6.1)]
506    (500, INTERNAL_SERVER_ERROR, "Internal Server Error");
507    /// 501 Not Implemented
508    /// [[RFC9110, Section 15.6.2](https://datatracker.ietf.org/doc/html/rfc9110#section-15.6.2)]
509    (501, NOT_IMPLEMENTED, "Not Implemented");
510    /// 502 Bad Gateway
511    /// [[RFC9110, Section 15.6.3](https://datatracker.ietf.org/doc/html/rfc9110#section-15.6.3)]
512    (502, BAD_GATEWAY, "Bad Gateway");
513    /// 503 Service Unavailable
514    /// [[RFC9110, Section 15.6.4](https://datatracker.ietf.org/doc/html/rfc9110#section-15.6.4)]
515    (503, SERVICE_UNAVAILABLE, "Service Unavailable");
516    /// 504 Gateway Timeout
517    /// [[RFC9110, Section 15.6.5](https://datatracker.ietf.org/doc/html/rfc9110#section-15.6.5)]
518    (504, GATEWAY_TIMEOUT, "Gateway Timeout");
519    /// 505 HTTP Version Not Supported
520    /// [[RFC9110, Section 15.6.6](https://datatracker.ietf.org/doc/html/rfc9110#section-15.6.6)]
521    (505, HTTP_VERSION_NOT_SUPPORTED, "HTTP Version Not Supported");
522    /// 506 Variant Also Negotiates
523    /// [[RFC2295, Section 8.1](https://datatracker.ietf.org/doc/html/rfc2295#section-8.1)]
524    (506, VARIANT_ALSO_NEGOTIATES, "Variant Also Negotiates");
525    /// 507 Insufficient Storage
526    /// [[RFC4918, Section 11.5](https://datatracker.ietf.org/doc/html/rfc4918#section-11.5)]
527    (507, INSUFFICIENT_STORAGE, "Insufficient Storage");
528    /// 508 Loop Detected
529    /// [[RFC5842, Section 7.2](https://datatracker.ietf.org/doc/html/rfc5842#section-7.2)]
530    (508, LOOP_DETECTED, "Loop Detected");
531
532    /// 510 Not Extended
533    /// [[RFC2774, Section 7](https://datatracker.ietf.org/doc/html/rfc2774#section-7)]
534    (510, NOT_EXTENDED, "Not Extended");
535    /// 511 Network Authentication Required
536    /// [[RFC6585, Section 6](https://datatracker.ietf.org/doc/html/rfc6585#section-6)]
537    (511, NETWORK_AUTHENTICATION_REQUIRED, "Network Authentication Required");
538}
539
540impl InvalidStatusCode {
541    const fn new() -> InvalidStatusCode {
542        InvalidStatusCode { _priv: () }
543    }
544}
545
546impl fmt::Debug for InvalidStatusCode {
547    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
548        f.debug_struct("InvalidStatusCode")
549            // skip _priv noise
550            .finish()
551    }
552}
553
554impl fmt::Display for InvalidStatusCode {
555    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
556        f.write_str("invalid status code")
557    }
558}
559
560impl Error for InvalidStatusCode {}
561
562// A string of packed 3-ASCII-digit status code values for the supported range
563// of [100, 999] (900 codes, 2700 bytes).
564const CODE_DIGITS: &str = "\
565100101102103104105106107108109110111112113114115116117118119\
566120121122123124125126127128129130131132133134135136137138139\
567140141142143144145146147148149150151152153154155156157158159\
568160161162163164165166167168169170171172173174175176177178179\
569180181182183184185186187188189190191192193194195196197198199\
570200201202203204205206207208209210211212213214215216217218219\
571220221222223224225226227228229230231232233234235236237238239\
572240241242243244245246247248249250251252253254255256257258259\
573260261262263264265266267268269270271272273274275276277278279\
574280281282283284285286287288289290291292293294295296297298299\
575300301302303304305306307308309310311312313314315316317318319\
576320321322323324325326327328329330331332333334335336337338339\
577340341342343344345346347348349350351352353354355356357358359\
578360361362363364365366367368369370371372373374375376377378379\
579380381382383384385386387388389390391392393394395396397398399\
580400401402403404405406407408409410411412413414415416417418419\
581420421422423424425426427428429430431432433434435436437438439\
582440441442443444445446447448449450451452453454455456457458459\
583460461462463464465466467468469470471472473474475476477478479\
584480481482483484485486487488489490491492493494495496497498499\
585500501502503504505506507508509510511512513514515516517518519\
586520521522523524525526527528529530531532533534535536537538539\
587540541542543544545546547548549550551552553554555556557558559\
588560561562563564565566567568569570571572573574575576577578579\
589580581582583584585586587588589590591592593594595596597598599\
590600601602603604605606607608609610611612613614615616617618619\
591620621622623624625626627628629630631632633634635636637638639\
592640641642643644645646647648649650651652653654655656657658659\
593660661662663664665666667668669670671672673674675676677678679\
594680681682683684685686687688689690691692693694695696697698699\
595700701702703704705706707708709710711712713714715716717718719\
596720721722723724725726727728729730731732733734735736737738739\
597740741742743744745746747748749750751752753754755756757758759\
598760761762763764765766767768769770771772773774775776777778779\
599780781782783784785786787788789790791792793794795796797798799\
600800801802803804805806807808809810811812813814815816817818819\
601820821822823824825826827828829830831832833834835836837838839\
602840841842843844845846847848849850851852853854855856857858859\
603860861862863864865866867868869870871872873874875876877878879\
604880881882883884885886887888889890891892893894895896897898899\
605900901902903904905906907908909910911912913914915916917918919\
606920921922923924925926927928929930931932933934935936937938939\
607940941942943944945946947948949950951952953954955956957958959\
608960961962963964965966967968969970971972973974975976977978979\
609980981982983984985986987988989990991992993994995996997998999";