use std::{error, fmt};
use http::StatusCode;
use crate::HttpError;
#[derive(Debug)]
pub struct StatusError {
status: StatusCode,
context: &'static str,
#[cfg(feature = "tracing")]
span: tracing::Span,
}
macro_rules! trait_fn {
($name:ident) => {
fn $name(self, context: &'static str) -> Result<T, StatusError>;
};
}
macro_rules! impl_fn {
($name:ident, $status:ident) => {
fn $name(self, context: &'static str) -> Result<T, StatusError> {
self.ok_or_else(|| StatusError {
status: StatusCode::$status,
context,
#[cfg(feature = "tracing")]
span: tracing::Span::current(),
})
}
};
}
pub trait OptionExt<T> {
trait_fn!(ok_or_bad_request);
trait_fn!(ok_or_unauthorized);
trait_fn!(ok_or_payment_required);
trait_fn!(ok_or_forbidden);
trait_fn!(ok_or_not_found);
trait_fn!(ok_or_method_not_allowed);
trait_fn!(ok_or_not_acceptable);
trait_fn!(ok_or_proxy_authentication_required);
trait_fn!(ok_or_request_timeout);
trait_fn!(ok_or_conflict);
trait_fn!(ok_or_gone);
trait_fn!(ok_or_length_required);
trait_fn!(ok_or_precondition_failed);
trait_fn!(ok_or_payload_too_large);
trait_fn!(ok_or_uri_too_long);
trait_fn!(ok_or_unsupported_media_type);
trait_fn!(ok_or_range_not_satisfiable);
trait_fn!(ok_or_expectation_failed);
trait_fn!(ok_or_im_a_teapot);
trait_fn!(ok_or_misdirected_request);
trait_fn!(ok_or_unprocessable_entity);
trait_fn!(ok_or_locked);
trait_fn!(ok_or_failed_dependency);
trait_fn!(ok_or_upgrade_required);
trait_fn!(ok_or_precondition_required);
trait_fn!(ok_or_too_many_requests);
trait_fn!(ok_or_request_header_fields_too_large);
trait_fn!(ok_or_unavailable_for_legal_reasons);
trait_fn!(ok_or_internal_server_error);
trait_fn!(ok_or_not_implemented);
trait_fn!(ok_or_bad_gateway);
trait_fn!(ok_or_service_unavailable);
trait_fn!(ok_or_gateway_timeout);
trait_fn!(ok_or_http_version_not_supported);
trait_fn!(ok_or_variant_also_negotiates);
trait_fn!(ok_or_insufficient_storage);
trait_fn!(ok_or_loop_detected);
trait_fn!(ok_or_not_extended);
trait_fn!(ok_or_network_authentication_required);
}
impl<T> OptionExt<T> for Option<T> {
impl_fn!(ok_or_bad_request, BAD_REQUEST);
impl_fn!(ok_or_unauthorized, UNAUTHORIZED);
impl_fn!(ok_or_payment_required, PAYMENT_REQUIRED);
impl_fn!(ok_or_forbidden, FORBIDDEN);
impl_fn!(ok_or_not_found, NOT_FOUND);
impl_fn!(ok_or_method_not_allowed, METHOD_NOT_ALLOWED);
impl_fn!(ok_or_not_acceptable, NOT_ACCEPTABLE);
impl_fn!(
ok_or_proxy_authentication_required,
PROXY_AUTHENTICATION_REQUIRED
);
impl_fn!(ok_or_request_timeout, REQUEST_TIMEOUT);
impl_fn!(ok_or_conflict, CONFLICT);
impl_fn!(ok_or_gone, GONE);
impl_fn!(ok_or_length_required, LENGTH_REQUIRED);
impl_fn!(ok_or_precondition_failed, PRECONDITION_FAILED);
impl_fn!(ok_or_payload_too_large, PAYLOAD_TOO_LARGE);
impl_fn!(ok_or_uri_too_long, URI_TOO_LONG);
impl_fn!(ok_or_unsupported_media_type, UNSUPPORTED_MEDIA_TYPE);
impl_fn!(ok_or_range_not_satisfiable, RANGE_NOT_SATISFIABLE);
impl_fn!(ok_or_expectation_failed, EXPECTATION_FAILED);
impl_fn!(ok_or_im_a_teapot, IM_A_TEAPOT);
impl_fn!(ok_or_misdirected_request, MISDIRECTED_REQUEST);
impl_fn!(ok_or_unprocessable_entity, UNPROCESSABLE_ENTITY);
impl_fn!(ok_or_locked, LOCKED);
impl_fn!(ok_or_failed_dependency, FAILED_DEPENDENCY);
impl_fn!(ok_or_upgrade_required, UPGRADE_REQUIRED);
impl_fn!(ok_or_precondition_required, PRECONDITION_REQUIRED);
impl_fn!(ok_or_too_many_requests, TOO_MANY_REQUESTS);
impl_fn!(
ok_or_request_header_fields_too_large,
REQUEST_HEADER_FIELDS_TOO_LARGE
);
impl_fn!(
ok_or_unavailable_for_legal_reasons,
UNAVAILABLE_FOR_LEGAL_REASONS
);
impl_fn!(ok_or_internal_server_error, INTERNAL_SERVER_ERROR);
impl_fn!(ok_or_not_implemented, NOT_IMPLEMENTED);
impl_fn!(ok_or_bad_gateway, BAD_GATEWAY);
impl_fn!(ok_or_service_unavailable, SERVICE_UNAVAILABLE);
impl_fn!(ok_or_gateway_timeout, GATEWAY_TIMEOUT);
impl_fn!(ok_or_http_version_not_supported, HTTP_VERSION_NOT_SUPPORTED);
impl_fn!(ok_or_variant_also_negotiates, VARIANT_ALSO_NEGOTIATES);
impl_fn!(ok_or_insufficient_storage, INSUFFICIENT_STORAGE);
impl_fn!(ok_or_loop_detected, LOOP_DETECTED);
impl_fn!(ok_or_not_extended, NOT_EXTENDED);
impl_fn!(
ok_or_network_authentication_required,
NETWORK_AUTHENTICATION_REQUIRED
);
}
impl error::Error for StatusError {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
None
}
}
impl fmt::Display for StatusError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.context)
}
}
impl HttpError for StatusError {
fn status_code(&self) -> StatusCode {
self.status
}
#[cfg(feature = "tracing")]
fn span(&self) -> Option<&tracing::Span> {
Some(&self.span)
}
}