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}