#![cfg_attr(feature = "fail-on-warnings", deny(warnings))]
#![warn(clippy::all, clippy::pedantic, clippy::nursery, clippy::cargo)]
#![allow(clippy::multiple_crate_versions)]
#[cfg(feature = "actix")]
pub mod actix;
#[cfg(feature = "reqwest")]
pub mod reqwest;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use strum::{AsRefStr, EnumString};
#[derive(Debug, Clone, Copy, EnumString, AsRefStr)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "SCREAMING_SNAKE_CASE"))]
#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
pub enum Method {
Get,
Post,
Put,
Patch,
Delete,
Head,
Options,
Connect,
Trace,
}
impl std::fmt::Display for Method {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.as_ref())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, EnumString, AsRefStr)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "SCREAMING_SNAKE_CASE"))]
#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
pub enum StatusCode {
Continue,
SwitchingProtocols,
Processing,
EarlyHints,
Ok,
Created,
Accepted,
NonAuthoritativeInformation,
NoContent,
ResetContent,
PartialContent,
MultiStatus,
AlreadyReported,
IMUsed,
MultipleChoices,
MovedPermanently,
Found,
SeeOther,
NotModified,
UseProxy,
TemporaryRedirect,
PermanentRedirect,
BadRequest,
Unauthorized,
PaymentRequired,
Forbidden,
NotFound,
MethodNotAllowed,
NotAcceptable,
ProxyAuthenticationRequired,
RequestTimeout,
Conflict,
Gone,
LengthRequired,
PreconditionFailed,
ContentTooLarge,
URITooLong,
UnsupportedMediaType,
RangeNotSatisfiable,
ExpectationFailed,
ImATeapot,
MisdirectedRequest,
UncompressableContent,
Locked,
FailedDependency,
TooEarly,
UpgradeRequired,
PreconditionRequired,
TooManyRequests,
RequestHeaderFieldsTooLarge,
UnavailableForLegalReasons,
InternalServerError,
NotImplemented,
BadGateway,
ServiceUnavailable,
GatewayTimeout,
HTTPVersionNotSupported,
VariantAlsoNegotiates,
InsufficientStorage,
LoopDetected,
NotExtended,
NetworkAuthenticationRequired,
}
impl From<StatusCode> for u16 {
fn from(value: StatusCode) -> Self {
match value {
StatusCode::Continue => 100,
StatusCode::SwitchingProtocols => 101,
StatusCode::Processing => 102,
StatusCode::EarlyHints => 103,
StatusCode::Ok => 200,
StatusCode::Created => 201,
StatusCode::Accepted => 202,
StatusCode::NonAuthoritativeInformation => 203,
StatusCode::NoContent => 204,
StatusCode::ResetContent => 205,
StatusCode::PartialContent => 206,
StatusCode::MultiStatus => 207,
StatusCode::AlreadyReported => 208,
StatusCode::IMUsed => 226,
StatusCode::MultipleChoices => 300,
StatusCode::MovedPermanently => 301,
StatusCode::Found => 302,
StatusCode::SeeOther => 303,
StatusCode::NotModified => 304,
StatusCode::UseProxy => 305,
StatusCode::TemporaryRedirect => 307,
StatusCode::PermanentRedirect => 308,
StatusCode::BadRequest => 400,
StatusCode::Unauthorized => 401,
StatusCode::PaymentRequired => 402,
StatusCode::Forbidden => 403,
StatusCode::NotFound => 404,
StatusCode::MethodNotAllowed => 405,
StatusCode::NotAcceptable => 406,
StatusCode::ProxyAuthenticationRequired => 407,
StatusCode::RequestTimeout => 408,
StatusCode::Conflict => 409,
StatusCode::Gone => 410,
StatusCode::LengthRequired => 411,
StatusCode::PreconditionFailed => 412,
StatusCode::ContentTooLarge => 413,
StatusCode::URITooLong => 414,
StatusCode::UnsupportedMediaType => 415,
StatusCode::RangeNotSatisfiable => 416,
StatusCode::ExpectationFailed => 417,
StatusCode::ImATeapot => 418,
StatusCode::MisdirectedRequest => 421,
StatusCode::UncompressableContent => 422,
StatusCode::Locked => 423,
StatusCode::FailedDependency => 424,
StatusCode::TooEarly => 425,
StatusCode::UpgradeRequired => 426,
StatusCode::PreconditionRequired => 428,
StatusCode::TooManyRequests => 429,
StatusCode::RequestHeaderFieldsTooLarge => 431,
StatusCode::UnavailableForLegalReasons => 451,
StatusCode::InternalServerError => 500,
StatusCode::NotImplemented => 501,
StatusCode::BadGateway => 502,
StatusCode::ServiceUnavailable => 503,
StatusCode::GatewayTimeout => 504,
StatusCode::HTTPVersionNotSupported => 505,
StatusCode::VariantAlsoNegotiates => 506,
StatusCode::InsufficientStorage => 507,
StatusCode::LoopDetected => 508,
StatusCode::NotExtended => 510,
StatusCode::NetworkAuthenticationRequired => 511,
}
}
}
#[derive(Debug, thiserror::Error)]
#[error("TryFromU16StatusCodeError")]
pub struct TryFromU16StatusCodeError;
impl TryFrom<u16> for StatusCode {
type Error = TryFromU16StatusCodeError;
fn try_from(value: u16) -> Result<Self, Self::Error> {
Ok(match value {
100 => Self::Continue,
101 => Self::SwitchingProtocols,
102 => Self::Processing,
103 => Self::EarlyHints,
200 => Self::Ok,
201 => Self::Created,
202 => Self::Accepted,
203 => Self::NonAuthoritativeInformation,
204 => Self::NoContent,
205 => Self::ResetContent,
206 => Self::PartialContent,
207 => Self::MultiStatus,
208 => Self::AlreadyReported,
226 => Self::IMUsed,
300 => Self::MultipleChoices,
301 => Self::MovedPermanently,
302 => Self::Found,
303 => Self::SeeOther,
304 => Self::NotModified,
305 => Self::UseProxy,
307 => Self::TemporaryRedirect,
308 => Self::PermanentRedirect,
400 => Self::BadRequest,
401 => Self::Unauthorized,
402 => Self::PaymentRequired,
403 => Self::Forbidden,
404 => Self::NotFound,
405 => Self::MethodNotAllowed,
406 => Self::NotAcceptable,
407 => Self::ProxyAuthenticationRequired,
408 => Self::RequestTimeout,
409 => Self::Conflict,
410 => Self::Gone,
411 => Self::LengthRequired,
412 => Self::PreconditionFailed,
413 => Self::ContentTooLarge,
414 => Self::URITooLong,
415 => Self::UnsupportedMediaType,
416 => Self::RangeNotSatisfiable,
417 => Self::ExpectationFailed,
418 => Self::ImATeapot,
421 => Self::MisdirectedRequest,
422 => Self::UncompressableContent,
423 => Self::Locked,
424 => Self::FailedDependency,
425 => Self::TooEarly,
426 => Self::UpgradeRequired,
428 => Self::PreconditionRequired,
429 => Self::TooManyRequests,
431 => Self::RequestHeaderFieldsTooLarge,
451 => Self::UnavailableForLegalReasons,
500 => Self::InternalServerError,
501 => Self::NotImplemented,
502 => Self::BadGateway,
503 => Self::ServiceUnavailable,
504 => Self::GatewayTimeout,
505 => Self::HTTPVersionNotSupported,
506 => Self::VariantAlsoNegotiates,
507 => Self::InsufficientStorage,
508 => Self::LoopDetected,
510 => Self::NotExtended,
511 => Self::NetworkAuthenticationRequired,
_ => {
return Err(TryFromU16StatusCodeError);
}
})
}
}
impl StatusCode {
#[must_use]
pub fn into_u16(self) -> u16 {
self.into()
}
#[must_use]
pub fn as_u16(&self) -> u16 {
(*self).into_u16()
}
pub fn try_from_u16(code: u16) -> Result<Self, TryFromU16StatusCodeError> {
code.try_into()
}
#[must_use]
pub fn from_u16(code: u16) -> Self {
Self::try_from_u16(code).unwrap()
}
}
impl StatusCode {
#[inline]
#[must_use]
pub fn is_informational(&self) -> bool {
(100..200).contains(&self.as_u16())
}
#[inline]
#[must_use]
pub fn is_success(&self) -> bool {
(200..300).contains(&self.as_u16())
}
#[inline]
#[must_use]
pub fn is_redirection(&self) -> bool {
(300..400).contains(&self.as_u16())
}
#[inline]
#[must_use]
pub fn is_client_error(&self) -> bool {
(400..500).contains(&self.as_u16())
}
#[inline]
#[must_use]
pub fn is_server_error(&self) -> bool {
(500..600).contains(&self.as_u16())
}
}
impl std::fmt::Display for StatusCode {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.as_ref())
}
}