Skip to main content

http_type/http_status/
impl.rs

1use super::*;
2
3/// The `HttpStatus` enum represents the HTTP status codes.
4///
5/// It maps common HTTP status codes to their respective meanings. It provides methods to retrieve
6/// the corresponding numeric code as well as the associated status text. Additionally, it implements
7/// conversion from a string representation of the status code.
8impl HttpStatus {
9    /// Gets the numeric HTTP status code.
10    ///
11    /// Returns the corresponding HTTP status code number for the enum variant.
12    ///
13    /// # Returns
14    ///
15    /// - `ResponseStatusCode` - The numeric status code.
16    pub fn code(&self) -> ResponseStatusCode {
17        match self {
18            Self::Continue => 100,
19            Self::SwitchingProtocols => 101,
20            Self::Processing => 102,
21            Self::EarlyHints => 103,
22            Self::Ok => 200,
23            Self::Created => 201,
24            Self::Accepted => 202,
25            Self::NonAuthoritativeInformation => 203,
26            Self::NoContent => 204,
27            Self::ResetContent => 205,
28            Self::PartialContent => 206,
29            Self::MultiStatus => 207,
30            Self::AlreadyReported => 208,
31            Self::IMUsed => 226,
32            Self::MultipleChoices => 300,
33            Self::MovedPermanently => 301,
34            Self::Found => 302,
35            Self::SeeOther => 303,
36            Self::NotModified => 304,
37            Self::UseProxy => 305,
38            Self::TemporaryRedirect => 307,
39            Self::PermanentRedirect => 308,
40            Self::BadRequest => 400,
41            Self::Unauthorized => 401,
42            Self::PaymentRequired => 402,
43            Self::Forbidden => 403,
44            Self::NotFound => 404,
45            Self::MethodNotAllowed => 405,
46            Self::NotAcceptable => 406,
47            Self::ProxyAuthenticationRequired => 407,
48            Self::RequestTimeout => 408,
49            Self::Conflict => 409,
50            Self::Gone => 410,
51            Self::LengthRequired => 411,
52            Self::PreconditionFailed => 412,
53            Self::PayloadTooLarge => 413,
54            Self::URITooLong => 414,
55            Self::UnsupportedMediaType => 415,
56            Self::RangeNotSatisfiable => 416,
57            Self::ExpectationFailed => 417,
58            Self::ImATeapot => 418,
59            Self::MisdirectedRequest => 421,
60            Self::UnprocessableEntity => 422,
61            Self::Locked => 423,
62            Self::FailedDependency => 424,
63            Self::TooEarly => 425,
64            Self::UpgradeRequired => 426,
65            Self::PreconditionRequired => 428,
66            Self::TooManyRequests => 429,
67            Self::RequestHeaderFieldsTooLarge => 431,
68            Self::UnavailableForLegalReasons => 451,
69            Self::InternalServerError => 500,
70            Self::NotImplemented => 501,
71            Self::BadGateway => 502,
72            Self::ServiceUnavailable => 503,
73            Self::GatewayTimeout => 504,
74            Self::HTTPVersionNotSupported => 505,
75            Self::VariantAlsoNegotiates => 506,
76            Self::InsufficientStorage => 507,
77            Self::LoopDetected => 508,
78            Self::NotExtended => 510,
79            Self::NetworkAuthenticationRequired => 511,
80            Self::Unknown => 0,
81        }
82    }
83
84    /// Gets the textual description for a status code.
85    ///
86    /// Returns the standard HTTP status text for the given numeric code.
87    ///
88    /// # Arguments
89    ///
90    /// - `ResponseStatusCode` - The numeric HTTP status code.
91    ///
92    /// # Returns
93    ///
94    /// - `String` - The standard status text description.
95    pub fn phrase(code: ResponseStatusCode) -> String {
96        Self::phrase_ref(code).to_owned()
97    }
98
99    /// Gets the textual description for a status code without copying it.
100    ///
101    /// The phrase of a status is a constant, so a caller that only reads it
102    /// borrows it rather than allocating a copy for every response.
103    ///
104    /// # Arguments
105    ///
106    /// - `ResponseStatusCode` - The numeric HTTP status code.
107    ///
108    /// # Returns
109    ///
110    /// - `&'static str` - The standard status text description.
111    pub fn phrase_ref(code: ResponseStatusCode) -> &'static str {
112        match code {
113            100 => CONTINUE,
114            101 => SWITCHING_PROTOCOLS,
115            102 => PROCESSING,
116            103 => EARLY_HINTS,
117            200 => OK,
118            201 => CREATED,
119            202 => ACCEPTED,
120            203 => NON_AUTHORITATIVE_INFORMATION,
121            204 => NO_CONTENT,
122            205 => RESET_CONTENT,
123            206 => PARTIAL_CONTENT,
124            207 => MULTI_STATUS,
125            208 => ALREADY_REPORTED,
126            226 => IM_USED,
127            300 => MULTIPLE_CHOICES,
128            301 => MOVED_PERMANENTLY,
129            302 => FOUND,
130            303 => SEE_OTHER,
131            304 => NOT_MODIFIED,
132            305 => USE_PROXY,
133            307 => TEMPORARY_REDIRECT,
134            308 => PERMANENT_REDIRECT,
135            400 => BAD_REQUEST,
136            401 => UNAUTHORIZED,
137            402 => PAYMENT_REQUIRED,
138            403 => FORBIDDEN,
139            404 => NOT_FOUND,
140            405 => METHOD_NOT_ALLOWED,
141            406 => NOT_ACCEPTABLE,
142            407 => PROXY_AUTHENTICATION_REQUIRED,
143            408 => REQUEST_TIMEOUT,
144            409 => CONFLICT,
145            410 => GONE,
146            411 => LENGTH_REQUIRED,
147            412 => PRECONDITION_FAILED,
148            413 => PAYLOAD_TOO_LARGE,
149            414 => URI_TOO_LONG,
150            415 => UNSUPPORTED_MEDIA_TYPE,
151            416 => RANGE_NOT_SATISFIABLE,
152            417 => EXPECTATION_FAILED,
153            418 => IM_A_TEAPOT,
154            421 => MISDIRECTED_REQUEST,
155            422 => UNPROCESSABLE_ENTITY,
156            423 => LOCKED,
157            424 => FAILED_DEPENDENCY,
158            425 => TOO_EARLY,
159            426 => UPGRADE_REQUIRED,
160            428 => PRECONDITION_REQUIRED,
161            429 => TOO_MANY_REQUESTS,
162            431 => REQUEST_HEADER_FIELDS_TOO_LARGE,
163            451 => UNAVAILABLE_FOR_LEGAL_REASONS,
164            500 => INTERNAL_SERVER_ERROR,
165            501 => NOT_IMPLEMENTED,
166            502 => BAD_GATEWAY,
167            503 => SERVICE_UNAVAILABLE,
168            504 => GATEWAY_TIMEOUT,
169            505 => HTTP_VERSION_NOT_SUPPORTED,
170            506 => VARIANT_ALSO_NEGOTIATES,
171            507 => INSUFFICIENT_STORAGE,
172            508 => LOOP_DETECTED,
173            510 => NOT_EXTENDED,
174            511 => NETWORK_AUTHENTICATION_REQUIRED,
175            _ => UNKNOWN,
176        }
177    }
178
179    /// Checks if status matches a string representation.
180    ///
181    /// Compares case-insensitively against both numeric code and text description.
182    ///
183    /// # Arguments
184    ///
185    /// - `C` - The string to compare against, which requires the `AsRef<str>` bound.
186    ///
187    /// # Returns
188    ///
189    /// - `bool` - True if the string matches either code or description.
190    pub fn same<C>(&self, code_str: C) -> bool
191    where
192        C: AsRef<str>,
193    {
194        self.to_string().eq_ignore_ascii_case(code_str.as_ref())
195    }
196}
197
198/// Implements the `Display` trait for `HttpStatus`, allowing it to be formatted as a string.
199impl Display for HttpStatus {
200    /// Formats the status code as text.
201    ///
202    /// # Arguments
203    ///
204    /// - `&mut Formatter<'_>` - The formatter to write to.
205    ///
206    /// # Returns
207    ///
208    /// - `fmt::Result` - The formatting result.
209    fn fmt(&self, data: &mut Formatter<'_>) -> fmt::Result {
210        let res: &str = match self {
211            Self::Continue => CONTINUE,
212            Self::SwitchingProtocols => SWITCHING_PROTOCOLS,
213            Self::Processing => PROCESSING,
214            Self::EarlyHints => EARLY_HINTS,
215            Self::Ok => OK,
216            Self::Created => CREATED,
217            Self::Accepted => ACCEPTED,
218            Self::NonAuthoritativeInformation => NON_AUTHORITATIVE_INFORMATION,
219            Self::NoContent => NO_CONTENT,
220            Self::ResetContent => RESET_CONTENT,
221            Self::PartialContent => PARTIAL_CONTENT,
222            Self::MultiStatus => MULTI_STATUS,
223            Self::AlreadyReported => ALREADY_REPORTED,
224            Self::IMUsed => IM_USED,
225            Self::MultipleChoices => MULTIPLE_CHOICES,
226            Self::MovedPermanently => MOVED_PERMANENTLY,
227            Self::Found => FOUND,
228            Self::SeeOther => SEE_OTHER,
229            Self::NotModified => NOT_MODIFIED,
230            Self::UseProxy => USE_PROXY,
231            Self::TemporaryRedirect => TEMPORARY_REDIRECT,
232            Self::PermanentRedirect => PERMANENT_REDIRECT,
233            Self::BadRequest => BAD_REQUEST,
234            Self::Unauthorized => UNAUTHORIZED,
235            Self::PaymentRequired => PAYMENT_REQUIRED,
236            Self::Forbidden => FORBIDDEN,
237            Self::NotFound => NOT_FOUND,
238            Self::MethodNotAllowed => METHOD_NOT_ALLOWED,
239            Self::NotAcceptable => NOT_ACCEPTABLE,
240            Self::ProxyAuthenticationRequired => PROXY_AUTHENTICATION_REQUIRED,
241            Self::RequestTimeout => REQUEST_TIMEOUT,
242            Self::Conflict => CONFLICT,
243            Self::Gone => GONE,
244            Self::LengthRequired => LENGTH_REQUIRED,
245            Self::PreconditionFailed => PRECONDITION_FAILED,
246            Self::PayloadTooLarge => PAYLOAD_TOO_LARGE,
247            Self::URITooLong => URI_TOO_LONG,
248            Self::UnsupportedMediaType => UNSUPPORTED_MEDIA_TYPE,
249            Self::RangeNotSatisfiable => RANGE_NOT_SATISFIABLE,
250            Self::ExpectationFailed => EXPECTATION_FAILED,
251            Self::ImATeapot => IM_A_TEAPOT,
252            Self::MisdirectedRequest => MISDIRECTED_REQUEST,
253            Self::UnprocessableEntity => UNPROCESSABLE_ENTITY,
254            Self::Locked => LOCKED,
255            Self::FailedDependency => FAILED_DEPENDENCY,
256            Self::TooEarly => TOO_EARLY,
257            Self::UpgradeRequired => UPGRADE_REQUIRED,
258            Self::PreconditionRequired => PRECONDITION_REQUIRED,
259            Self::TooManyRequests => TOO_MANY_REQUESTS,
260            Self::RequestHeaderFieldsTooLarge => REQUEST_HEADER_FIELDS_TOO_LARGE,
261            Self::UnavailableForLegalReasons => UNAVAILABLE_FOR_LEGAL_REASONS,
262            Self::InternalServerError => INTERNAL_SERVER_ERROR,
263            Self::NotImplemented => NOT_IMPLEMENTED,
264            Self::BadGateway => BAD_GATEWAY,
265            Self::ServiceUnavailable => SERVICE_UNAVAILABLE,
266            Self::GatewayTimeout => GATEWAY_TIMEOUT,
267            Self::HTTPVersionNotSupported => HTTP_VERSION_NOT_SUPPORTED,
268            Self::VariantAlsoNegotiates => VARIANT_ALSO_NEGOTIATES,
269            Self::InsufficientStorage => INSUFFICIENT_STORAGE,
270            Self::LoopDetected => LOOP_DETECTED,
271            Self::NotExtended => NOT_EXTENDED,
272            Self::NetworkAuthenticationRequired => NETWORK_AUTHENTICATION_REQUIRED,
273            Self::Unknown => UNKNOWN,
274        };
275        write!(data, "{res}")
276    }
277}
278
279/// Implements the `FromStr` trait for `HttpStatus`, allowing conversion from a string slice.
280impl FromStr for HttpStatus {
281    /// The error type returned when conversion fails.
282    type Err = ();
283
284    /// Parses a string into an HttpStatus.
285    ///
286    /// Attempts to convert the string to a numeric code and match known status codes.
287    ///
288    /// # Arguments
289    ///
290    /// - `&str` - The string to parse.
291    ///
292    /// # Returns
293    ///
294    /// - `Result<Self, Self::Err>` - The parsed status or error.
295    fn from_str(code_str: &str) -> Result<Self, Self::Err> {
296        if let Ok(code) = code_str.parse::<ResponseStatusCode>() {
297            match code {
298                100 => Ok(Self::Continue),
299                101 => Ok(Self::SwitchingProtocols),
300                102 => Ok(Self::Processing),
301                103 => Ok(Self::EarlyHints),
302                200 => Ok(Self::Ok),
303                201 => Ok(Self::Created),
304                202 => Ok(Self::Accepted),
305                203 => Ok(Self::NonAuthoritativeInformation),
306                204 => Ok(Self::NoContent),
307                205 => Ok(Self::ResetContent),
308                206 => Ok(Self::PartialContent),
309                207 => Ok(Self::MultiStatus),
310                208 => Ok(Self::AlreadyReported),
311                226 => Ok(Self::IMUsed),
312                300 => Ok(Self::MultipleChoices),
313                301 => Ok(Self::MovedPermanently),
314                302 => Ok(Self::Found),
315                303 => Ok(Self::SeeOther),
316                304 => Ok(Self::NotModified),
317                305 => Ok(Self::UseProxy),
318                307 => Ok(Self::TemporaryRedirect),
319                308 => Ok(Self::PermanentRedirect),
320                400 => Ok(Self::BadRequest),
321                401 => Ok(Self::Unauthorized),
322                402 => Ok(Self::PaymentRequired),
323                403 => Ok(Self::Forbidden),
324                404 => Ok(Self::NotFound),
325                405 => Ok(Self::MethodNotAllowed),
326                406 => Ok(Self::NotAcceptable),
327                407 => Ok(Self::ProxyAuthenticationRequired),
328                408 => Ok(Self::RequestTimeout),
329                409 => Ok(Self::Conflict),
330                410 => Ok(Self::Gone),
331                411 => Ok(Self::LengthRequired),
332                412 => Ok(Self::PreconditionFailed),
333                413 => Ok(Self::PayloadTooLarge),
334                414 => Ok(Self::URITooLong),
335                415 => Ok(Self::UnsupportedMediaType),
336                416 => Ok(Self::RangeNotSatisfiable),
337                417 => Ok(Self::ExpectationFailed),
338                418 => Ok(Self::ImATeapot),
339                421 => Ok(Self::MisdirectedRequest),
340                422 => Ok(Self::UnprocessableEntity),
341                423 => Ok(Self::Locked),
342                424 => Ok(Self::FailedDependency),
343                425 => Ok(Self::TooEarly),
344                426 => Ok(Self::UpgradeRequired),
345                428 => Ok(Self::PreconditionRequired),
346                429 => Ok(Self::TooManyRequests),
347                431 => Ok(Self::RequestHeaderFieldsTooLarge),
348                451 => Ok(Self::UnavailableForLegalReasons),
349                500 => Ok(Self::InternalServerError),
350                501 => Ok(Self::NotImplemented),
351                502 => Ok(Self::BadGateway),
352                503 => Ok(Self::ServiceUnavailable),
353                504 => Ok(Self::GatewayTimeout),
354                505 => Ok(Self::HTTPVersionNotSupported),
355                506 => Ok(Self::VariantAlsoNegotiates),
356                507 => Ok(Self::InsufficientStorage),
357                508 => Ok(Self::LoopDetected),
358                510 => Ok(Self::NotExtended),
359                511 => Ok(Self::NetworkAuthenticationRequired),
360                _ => Ok(Self::Unknown),
361            }
362        } else {
363            Ok(Self::Unknown)
364        }
365    }
366}