Documentation
/// Define an error type implemented as an empty `struct`.
///
/// The first argument is the type name. The second optional argument is the
/// [Display](std::fmt::Display) representation, which defaults to the type name.
#[macro_export]
macro_rules! tag_error {
    ( $type:ident $(,)? ) => {
        $crate::tag_error!($type, stringify!($type));
    };

    ( $type:ident, $display:expr $(,)? ) => {
        #[doc = concat!(stringify!($type), " tag error.")]
        #[derive(Clone, Copy, Debug, Default)]
        pub struct $type;

        impl $type {
            /// Problem constructor.
            #[track_caller]
            pub fn as_problem() -> $crate::Problem {
                $crate::Problem::from(Self)
            }
        }

        impl ::std::fmt::Display for $type {
            fn fmt(&self, formatter: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                ::std::write!(formatter, "{}", $display)
            }
        }

        impl ::std::error::Error for $type {}

        impl ::std::cmp::PartialEq for $type {
            fn eq(&self, _other: &Self) -> bool {
                true
            }
        }

        impl ::std::cmp::Eq for $type {}

        impl ::std::cmp::PartialOrd for $type {
            fn partial_cmp(&self, _other: &Self) -> ::std::option::Option<::std::cmp::Ordering> {
                ::std::option::Option::Some(::std::cmp::Ordering::Equal)
            }
        }

        impl ::std::cmp::Ord for $type {
            fn cmp(&self, _other: &Self) -> ::std::cmp::Ordering {
                ::std::cmp::Ordering::Equal
            }
        }
    };
}

#[allow(unused_imports)]
pub use tag_error;