Skip to main content

sark_http/payload/response/
status.rs

1use std::num::NonZero;
2
3/// An admitted three-digit HTTP response status.
4#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
5#[repr(transparent)]
6pub struct Code(NonZero<u16>);
7
8#[derive(Clone, Copy, Debug, PartialEq, Eq)]
9pub struct Error {
10    actual: u16,
11}
12
13impl Code {
14    pub const CONTINUE: Self = Self::exact::<100>();
15    pub const SWITCHING_PROTOCOLS: Self = Self::exact::<101>();
16    pub const PROCESSING: Self = Self::exact::<102>();
17    pub const EARLY_HINTS: Self = Self::exact::<103>();
18    pub const OK: Self = Self::exact::<200>();
19    pub const CREATED: Self = Self::exact::<201>();
20    pub const ACCEPTED: Self = Self::exact::<202>();
21    pub const NON_AUTHORITATIVE_INFORMATION: Self = Self::exact::<203>();
22    pub const NO_CONTENT: Self = Self::exact::<204>();
23    pub const RESET_CONTENT: Self = Self::exact::<205>();
24    pub const PARTIAL_CONTENT: Self = Self::exact::<206>();
25    pub const MULTI_STATUS: Self = Self::exact::<207>();
26    pub const ALREADY_REPORTED: Self = Self::exact::<208>();
27    pub const IM_USED: Self = Self::exact::<226>();
28    pub const MULTIPLE_CHOICES: Self = Self::exact::<300>();
29    pub const MOVED_PERMANENTLY: Self = Self::exact::<301>();
30    pub const FOUND: Self = Self::exact::<302>();
31    pub const SEE_OTHER: Self = Self::exact::<303>();
32    pub const NOT_MODIFIED: Self = Self::exact::<304>();
33    pub const USE_PROXY: Self = Self::exact::<305>();
34    pub const TEMPORARY_REDIRECT: Self = Self::exact::<307>();
35    pub const PERMANENT_REDIRECT: Self = Self::exact::<308>();
36    pub const BAD_REQUEST: Self = Self::exact::<400>();
37    pub const UNAUTHORIZED: Self = Self::exact::<401>();
38    pub const PAYMENT_REQUIRED: Self = Self::exact::<402>();
39    pub const FORBIDDEN: Self = Self::exact::<403>();
40    pub const NOT_FOUND: Self = Self::exact::<404>();
41    pub const METHOD_NOT_ALLOWED: Self = Self::exact::<405>();
42    pub const NOT_ACCEPTABLE: Self = Self::exact::<406>();
43    pub const PROXY_AUTHENTICATION_REQUIRED: Self = Self::exact::<407>();
44    pub const REQUEST_TIMEOUT: Self = Self::exact::<408>();
45    pub const CONFLICT: Self = Self::exact::<409>();
46    pub const GONE: Self = Self::exact::<410>();
47    pub const LENGTH_REQUIRED: Self = Self::exact::<411>();
48    pub const PRECONDITION_FAILED: Self = Self::exact::<412>();
49    pub const PAYLOAD_TOO_LARGE: Self = Self::exact::<413>();
50    pub const URI_TOO_LONG: Self = Self::exact::<414>();
51    pub const UNSUPPORTED_MEDIA_TYPE: Self = Self::exact::<415>();
52    pub const RANGE_NOT_SATISFIABLE: Self = Self::exact::<416>();
53    pub const EXPECTATION_FAILED: Self = Self::exact::<417>();
54    pub const IM_A_TEAPOT: Self = Self::exact::<418>();
55    pub const MISDIRECTED_REQUEST: Self = Self::exact::<421>();
56    pub const UNPROCESSABLE_ENTITY: Self = Self::exact::<422>();
57    pub const LOCKED: Self = Self::exact::<423>();
58    pub const FAILED_DEPENDENCY: Self = Self::exact::<424>();
59    pub const TOO_EARLY: Self = Self::exact::<425>();
60    pub const UPGRADE_REQUIRED: Self = Self::exact::<426>();
61    pub const PRECONDITION_REQUIRED: Self = Self::exact::<428>();
62    pub const TOO_MANY_REQUESTS: Self = Self::exact::<429>();
63    pub const REQUEST_HEADER_FIELDS_TOO_LARGE: Self = Self::exact::<431>();
64    pub const UNAVAILABLE_FOR_LEGAL_REASONS: Self = Self::exact::<451>();
65    pub const INTERNAL_SERVER_ERROR: Self = Self::exact::<500>();
66    pub const NOT_IMPLEMENTED: Self = Self::exact::<501>();
67    pub const BAD_GATEWAY: Self = Self::exact::<502>();
68    pub const SERVICE_UNAVAILABLE: Self = Self::exact::<503>();
69    pub const GATEWAY_TIMEOUT: Self = Self::exact::<504>();
70    pub const HTTP_VERSION_NOT_SUPPORTED: Self = Self::exact::<505>();
71    pub const VARIANT_ALSO_NEGOTIATES: Self = Self::exact::<506>();
72    pub const INSUFFICIENT_STORAGE: Self = Self::exact::<507>();
73    pub const LOOP_DETECTED: Self = Self::exact::<508>();
74    pub const NOT_EXTENDED: Self = Self::exact::<510>();
75    pub const NETWORK_AUTHENTICATION_REQUIRED: Self = Self::exact::<511>();
76
77    /// Admits known and extension statuses within the five HTTP status classes.
78    pub const fn from_u16(actual: u16) -> Result<Self, Error> {
79        if actual < 100 || actual > 599 {
80            return Err(Error { actual });
81        }
82        Ok(Self(NonZero::<u16>::MIN.saturating_add(actual - 1)))
83    }
84
85    pub const fn as_u16(&self) -> u16 {
86        self.0.get()
87    }
88
89    pub const fn as_bytes(&self) -> [u8; 3] {
90        let value = self.as_u16();
91        [
92            b'0' + (value / 100) as u8,
93            b'0' + ((value / 10) % 10) as u8,
94            b'0' + (value % 10) as u8,
95        ]
96    }
97
98    pub const fn is_info(&self) -> bool {
99        self.as_u16() / 100 == 1
100    }
101
102    pub const fn is_success(&self) -> bool {
103        self.as_u16() / 100 == 2
104    }
105
106    pub const fn reason(&self) -> Option<&str> {
107        match self.as_u16() {
108            100 => Some("Continue"),
109            101 => Some("Switching Protocols"),
110            102 => Some("Processing"),
111            103 => Some("Early Hints"),
112            200 => Some("OK"),
113            201 => Some("Created"),
114            202 => Some("Accepted"),
115            203 => Some("Non Authoritative Information"),
116            204 => Some("No Content"),
117            205 => Some("Reset Content"),
118            206 => Some("Partial Content"),
119            207 => Some("Multi-Status"),
120            208 => Some("Already Reported"),
121            226 => Some("IM Used"),
122            300 => Some("Multiple Choices"),
123            301 => Some("Moved Permanently"),
124            302 => Some("Found"),
125            303 => Some("See Other"),
126            304 => Some("Not Modified"),
127            305 => Some("Use Proxy"),
128            307 => Some("Temporary Redirect"),
129            308 => Some("Permanent Redirect"),
130            400 => Some("Bad Request"),
131            401 => Some("Unauthorized"),
132            402 => Some("Payment Required"),
133            403 => Some("Forbidden"),
134            404 => Some("Not Found"),
135            405 => Some("Method Not Allowed"),
136            406 => Some("Not Acceptable"),
137            407 => Some("Proxy Authentication Required"),
138            408 => Some("Request Timeout"),
139            409 => Some("Conflict"),
140            410 => Some("Gone"),
141            411 => Some("Length Required"),
142            412 => Some("Precondition Failed"),
143            413 => Some("Payload Too Large"),
144            414 => Some("URI Too Long"),
145            415 => Some("Unsupported Media Type"),
146            416 => Some("Range Not Satisfiable"),
147            417 => Some("Expectation Failed"),
148            418 => Some("I'm a teapot"),
149            421 => Some("Misdirected Request"),
150            422 => Some("Unprocessable Entity"),
151            423 => Some("Locked"),
152            424 => Some("Failed Dependency"),
153            425 => Some("Too Early"),
154            426 => Some("Upgrade Required"),
155            428 => Some("Precondition Required"),
156            429 => Some("Too Many Requests"),
157            431 => Some("Request Header Fields Too Large"),
158            451 => Some("Unavailable For Legal Reasons"),
159            500 => Some("Internal Server Error"),
160            501 => Some("Not Implemented"),
161            502 => Some("Bad Gateway"),
162            503 => Some("Service Unavailable"),
163            504 => Some("Gateway Timeout"),
164            505 => Some("HTTP Version Not Supported"),
165            506 => Some("Variant Also Negotiates"),
166            507 => Some("Insufficient Storage"),
167            508 => Some("Loop Detected"),
168            510 => Some("Not Extended"),
169            511 => Some("Network Authentication Required"),
170            _ => None,
171        }
172    }
173
174    const fn exact<const VALUE: u16>() -> Self {
175        const { assert!(VALUE >= 100 && VALUE <= 599) };
176        Self(NonZero::<u16>::MIN.saturating_add(VALUE - 1))
177    }
178}
179
180impl Default for Code {
181    fn default() -> Self {
182        Self::OK
183    }
184}
185
186impl From<Code> for u16 {
187    fn from(code: Code) -> Self {
188        code.as_u16()
189    }
190}
191
192impl Error {
193    pub const fn actual(self) -> u16 {
194        self.actual
195    }
196}
197
198const _: () = {
199    assert!(size_of::<Code>() == size_of::<u16>());
200    assert!(size_of::<Option<Code>>() == size_of::<Code>());
201    assert!(size_of::<Error>() == size_of::<u16>());
202    assert!(!std::mem::needs_drop::<Code>());
203    assert!(!std::mem::needs_drop::<Error>());
204};