twilight_http/response/status_code.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
use std::fmt::{Display, Formatter, Result as FmtResult};
/// Status code of a response.
///
/// Constants are defined for the response codes that Discord defines in their [response code table].
///
/// # Comparing the status code
///
/// Status codes can easily be compared with status code integers due to
/// implementing `PartialEq<u16>`. This is equivalent to checking against the
/// value returned by [`StatusCode::get`].
///
/// [response code table]: https://discord.com/developers/docs/topics/opcodes-and-status-codes#http-http-response-codes
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct StatusCode(u16);
impl StatusCode {
/// Create a new status code from a raw status code.
pub(crate) const fn new(code: u16) -> Self {
// We don't need to do any checking that the status code is valid since
// the value always comes from `hyper`'s status code implementation.
Self(code)
}
/// Raw status code value.
#[must_use = "status code must be used to be useful"]
pub const fn get(self) -> u16 {
self.0
}
/// Whether the status code is informational.
///
/// This is defined as being between `[100, 200)`.
#[must_use = "whether a status code is informational must be used"]
pub const fn is_informational(self) -> bool {
self.in_range(100, 200)
}
/// Whether the status code is a success.
///
/// This is defined as being between `[200, 300)`.
#[must_use = "whether a status code is a success must be used"]
pub const fn is_success(self) -> bool {
self.in_range(200, 300)
}
/// Whether the status code is a redirection.
///
/// This is defined as being between `[300, 400)`.
#[must_use = "whether a status code is redirectional must be used"]
pub const fn is_redirection(self) -> bool {
self.in_range(300, 400)
}
/// Whether the status code is a client error.
///
/// This is defined as being between `[400, 500)`.
#[must_use = "whether a status code is a client error must be used"]
pub const fn is_client_error(self) -> bool {
self.in_range(400, 500)
}
/// Whether the status code is a server error.
///
/// This is defined as being between `[500, 600)`.
#[must_use = "whether a status code is a server error must be used"]
pub const fn is_server_error(self) -> bool {
self.in_range(500, 600)
}
/// Whether the status code is within a range.
///
/// The range is defined as `[min, max)`.
const fn in_range(self, min: u16, max: u16) -> bool {
self.0 >= min && self.0 < max
}
/// 200 (OK) The request completed successfully.
pub const OK: StatusCode = StatusCode::new(200);
/// 201 (CREATED) The entity was created successfully.
pub const CREATED: StatusCode = StatusCode::new(201);
/// 204 (NO CONTENT) The request completed successfully but returned no content.
pub const NO_CONTENT: StatusCode = StatusCode::new(204);
/// 304 (NOT MODIFIED) The entity was not modified (no action was taken).
pub const NOT_MODIFIED: StatusCode = StatusCode::new(304);
/// 400 (BAD REQUEST) The request was improperly formatted, or the server couldn't understand it.
pub const BAD_REQUEST: StatusCode = StatusCode::new(400);
/// 401 (UNAUTHORIZED) The Authorization header was missing or invalid.
pub const UNAUTHORIZED: StatusCode = StatusCode::new(401);
/// 403 (FORBIDDEN) The Authorization token you passed did not have permission to the resource.
pub const FORBIDDEN: StatusCode = StatusCode::new(403);
/// 404 (NOT FOUND) The resource at the location specified doesn't exist.
pub const NOT_FOUND: StatusCode = StatusCode::new(404);
/// 405 (METHOD NOT ALLOWED) The HTTP method used is not valid for the location specified.
pub const METHOD_NOT_ALLOWED: StatusCode = StatusCode::new(405);
/// 429 (TOO MANY REQUESTS) You are being rate limited, see Rate Limits.
pub const TOO_MANY_REQUESTS: StatusCode = StatusCode::new(429);
/// 502 (GATEWAY UNAVAILABLE) There was not a gateway available to process your request. Wait a bit and retry.
pub const GATEWAY_UNAVAILABLE: StatusCode = StatusCode::new(502);
}
impl Display for StatusCode {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
self.0.fmt(f)
}
}
impl PartialEq<u16> for StatusCode {
fn eq(&self, other: &u16) -> bool {
self.get() == *other
}
}
impl PartialEq<StatusCode> for u16 {
fn eq(&self, other: &StatusCode) -> bool {
*self == other.get()
}
}
#[cfg(test)]
mod tests {
use super::StatusCode;
use static_assertions::assert_impl_all;
use std::{
fmt::{Debug, Display},
hash::Hash,
};
assert_impl_all!(
StatusCode: Clone,
Copy,
Debug,
Display,
Eq,
Hash,
PartialEq,
PartialOrd,
Ord,
Send,
Sync
);
#[test]
fn eq_with_integer() {
assert_eq!(200_u16, StatusCode::new(200));
assert_eq!(StatusCode::new(404), 404_u16);
}
/// Test that [`StatusCode::get`] returns the raw value of the status code.
///
/// Notably what we want to test here is that it's not repeatedly returning
/// the same value (as if it were hardcoded), and that it's instead
/// returning the provided value.
#[test]
fn get() {
assert_eq!(200, StatusCode::new(200).get());
assert_eq!(403, StatusCode::new(403).get());
assert_eq!(404, StatusCode::new(404).get());
}
#[test]
fn ranges() {
assert!(StatusCode::new(100).is_informational());
assert!(StatusCode::new(199).is_informational());
assert!(StatusCode::new(200).is_success());
assert!(StatusCode::new(299).is_success());
assert!(StatusCode::new(300).is_redirection());
assert!(StatusCode::new(399).is_redirection());
assert!(StatusCode::new(400).is_client_error());
assert!(StatusCode::new(499).is_client_error());
assert!(StatusCode::new(500).is_server_error());
assert!(StatusCode::new(599).is_server_error());
}
}