macro_rules! impl_error {
($ty:ident,$message:expr) => {
#[doc = concat!("The error type of `", stringify!($ty), "`.")]
#[derive(Debug)]
pub struct $ty {
_priv: (),
}
impl $ty {
pub(crate) fn new() -> Self {
Self { _priv: () }
}
}
impl core::fmt::Display for $ty {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.write_str($message)
}
}
impl core::error::Error for $ty {}
};
}
#[macro_export]
macro_rules! http_error_fmt {
($(#[$meta:meta])* $vis:vis $name:ident, $status:expr, |$ty_self:pat, $fmt:ident| $body:expr $(,)?) => {
$(#[$meta])*
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
$vis struct $name {
_priv: (),
}
impl $name {
pub const fn new() -> Self {
Self { _priv: () }
}
}
impl ::core::default::Default for $name {
fn default() -> Self {
Self::new()
}
}
impl ::core::fmt::Display for $name {
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
let $ty_self = self;
let $fmt = f;
$body
}
}
impl ::core::error::Error for $name {}
impl $crate::HttpError for $name {
fn status(&self) -> $crate::StatusCode {
$status
}
}
};
}
#[macro_export]
macro_rules! http_error {
($(#[$meta:meta])* $vis:vis $name:ident, $status:expr, $message:expr $(,)?) => {
$crate::http_error_fmt!(
$(#[$meta])*
$vis $name,
$status,
|_, f| { f.write_str($message) },
);
};
}
#[cfg(test)]
mod tests {
use crate::{HttpError, StatusCode};
use alloc::string::ToString;
http_error!(
pub MacroNotFound,
StatusCode::NOT_FOUND,
"macro missing"
);
http_error_fmt!(
pub MacroDisplayError,
StatusCode::BAD_REQUEST,
|_, f| write!(f, "bad request (400)"),
);
#[test]
fn http_error_macros_create_expected_types() {
let not_found = MacroNotFound::new();
assert_eq!(not_found.status(), StatusCode::NOT_FOUND);
assert_eq!(not_found.to_string(), "macro missing");
let display = MacroDisplayError::new();
assert_eq!(display.status(), StatusCode::BAD_REQUEST);
assert_eq!(display.to_string(), "bad request (400)");
}
}