safe_http/status/
code.rs

1use super::InvalidStatusCode;
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
4pub struct StatusCode(u16);
5
6impl StatusCode {
7    #[inline]
8    pub fn to_u16(self) -> u16 {
9        self.0
10    }
11
12    #[inline]
13    pub fn try_from_u16(code: u16) -> Result<Self, InvalidStatusCode> {
14        if is_valid_status_code(code) {
15            Ok(Self(code))
16        } else {
17            Err(InvalidStatusCode { code })
18        }
19    }
20
21    pub(super) const fn internal_from_const_u16(code: u16) -> Self {
22        if !is_valid_status_code(code) {
23            #[allow(unconditional_panic, clippy::no_effect)]
24            ([] as [u8; 0])[0]; // hack for panic in const fn,
25        }
26        Self(code)
27    }
28
29    pub fn is_informational(self) -> bool {
30        matches!(self.to_u16(), 100..=199)
31    }
32
33    pub fn is_successful(self) -> bool {
34        matches!(self.to_u16(), 200..=299)
35    }
36
37    pub fn is_redirection(self) -> bool {
38        matches!(self.to_u16(), 300..=399)
39    }
40
41    pub fn is_client_error(self) -> bool {
42        matches!(self.to_u16(), 400..=499)
43    }
44
45    pub fn is_server_error(self) -> bool {
46        matches!(self.to_u16(), 500..=599)
47    }
48}
49
50impl Default for StatusCode {
51    fn default() -> Self {
52        Self::OK
53    }
54}
55
56impl From<StatusCode> for u16 {
57    #[inline]
58    fn from(s: StatusCode) -> Self {
59        s.to_u16()
60    }
61}
62
63impl PartialEq<u16> for StatusCode {
64    #[inline]
65    fn eq(&self, other: &u16) -> bool {
66        self.to_u16().eq(other)
67    }
68}
69
70impl PartialOrd<u16> for StatusCode {
71    #[inline]
72    fn partial_cmp(&self, other: &u16) -> Option<std::cmp::Ordering> {
73        self.to_u16().partial_cmp(other)
74    }
75}
76
77const fn is_valid_status_code(code: u16) -> bool {
78    matches!(code, 100..=599)
79}
80
81#[cfg(test)]
82mod tests {
83    use super::*;
84    use assert_matches::assert_matches;
85
86    #[test]
87    fn generated_constants_are_valid() {
88        for constant in StatusCode::GENERATED_CONSTANTS.iter().map(|c| c.to_u16()) {
89            // Invalid constants are a compile error if those constants are used.
90            // So these asserts are just there to double check.
91            assert_matches!(StatusCode::try_from_u16(constant), Ok(x) => assert_eq!(x, constant));
92        }
93    }
94}