retina_fetch/
status_code.rs

1// Copyright (C) 2023 Tristan Gerritsen <tristan@thewoosh.org>
2// All Rights Reserved.
3
4/// A convenient wrapper for the [HTTP Status Code][spec].
5///
6/// [spec]: https://httpwg.org/specs/rfc9110.html#status.codes
7#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
8pub struct StatusCode(u16);
9
10impl StatusCode {
11    /// Get the numeric value of this status code.
12    pub fn as_u16(&self) -> u16 {
13        self.0
14    }
15
16    /// The class of the status code determine the result of the request and the
17    /// semantics of the response.
18    pub fn class(&self) -> StatusCodeClass {
19        match self.0 {
20            100..=199 => StatusCodeClass::Informational,
21            200..=299 => StatusCodeClass::Successful,
22            300..=339 => StatusCodeClass::Redirection,
23            400..=499 => StatusCodeClass::ClientError,
24            500..=599 => StatusCodeClass::ServerError,
25            _ => panic!("invalid value: {}", self.0)
26        }
27    }
28
29    /// Checks if the status code is of the _client error_ class, i.e. 4xx.
30    pub fn is_client_error(&self) -> bool {
31        self.class().is_client_error()
32    }
33
34    /// Checks if the status code is of the _informational_ class, i.e. 1xx.
35    pub fn is_informational(&self) -> bool {
36        self.class().is_informational()
37    }
38
39    /// Checks if the status code is of the _redirection_ class, i.e. 3xx.
40    pub fn is_redirection(&self) -> bool {
41        self.class().is_redirection()
42    }
43
44    /// Checks if the status code is of the _server error_ class, i.e. 5xx.
45    pub fn is_server_error(&self) -> bool {
46        self.class().is_server_error()
47    }
48
49    /// Checks if the status code is of the _successful_ class, i.e. 2xx.
50    pub fn is_successful(&self) -> bool {
51        self.class().is_successful()
52    }
53}
54
55/// The class of the status code determine the result of the request and the
56/// semantics of the response.
57///
58/// # References
59/// * [RFC 9110: HTTP Semantics ยง 15][spec]
60///
61/// [spec]: https://www.rfc-editor.org/rfc/rfc9110.html#section-15
62#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
63pub enum StatusCodeClass {
64    /// The request was received, continuing process.
65    Informational,
66
67    /// The request was successfully received, understood, and accepted.
68    Successful,
69
70    /// Further action needs to be taken in order to complete the request.
71    Redirection,
72
73    /// The request contains bad syntax or cannot be fulfilled.
74    ClientError,
75
76    /// The server failed to fulfill an apparently valid request.
77    ServerError,
78}
79
80impl StatusCodeClass {
81    /// Checks if the status code is of the _client error_ class, i.e. 4xx.
82    pub const fn is_client_error(&self) -> bool {
83        matches!(self, StatusCodeClass::ClientError)
84    }
85
86    /// Checks if the status code is of the _informational_ class, i.e. 1xx.
87    pub const fn is_informational(&self) -> bool {
88        matches!(self, StatusCodeClass::Informational)
89    }
90
91    /// Checks if the status code is of the _redirection_ class, i.e. 3xx.
92    pub const fn is_redirection(&self) -> bool {
93        matches!(self, StatusCodeClass::Redirection)
94    }
95
96    /// Checks if the status code is of the _server error_ class, i.e. 5xx.
97    pub const fn is_server_error(&self) -> bool {
98        matches!(self, StatusCodeClass::ServerError)
99    }
100
101    /// Checks if the status code is of the _successful_ class, i.e. 2xx.
102    pub const fn is_successful(&self) -> bool {
103        matches!(self, StatusCodeClass::Successful)
104    }
105}
106
107impl From<hyper::StatusCode> for StatusCode {
108    fn from(value: hyper::StatusCode) -> Self {
109        assert!(value.as_u16() >= 100, "invalid status code");
110        assert!(value.as_u16() <= 599, "invalid status code");
111        Self(value.as_u16())
112    }
113}