macro_rules! rule_ids {
(
$(#[$enum_meta:meta])*
$name:ident {
$($variant:ident => $text:literal),+ $(,)?
}
) => {
$(#[$enum_meta])*
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum $name {
$(
#[doc = concat!("The `", $text, "` rule.")]
$variant
),+
}
impl $name {
pub const ALL: &'static [Self] = &[$(Self::$variant),+];
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
$(Self::$variant => $text),+
}
}
}
impl ::std::fmt::Display for $name {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
f.write_str(self.as_str())
}
}
impl ::std::str::FromStr for $name {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::ALL
.iter()
.copied()
.find(|variant| variant.as_str() == s)
.ok_or_else(|| format!("unrecognized rule name: {s}"))
}
}
impl ::serde::Serialize for $name {
fn serialize<S: ::serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
serializer.serialize_str(self.as_str())
}
}
impl<'de> ::serde::Deserialize<'de> for $name {
fn deserialize<D: ::serde::Deserializer<'de>>(
deserializer: D,
) -> Result<Self, D::Error> {
let raw = <String as ::serde::Deserialize>::deserialize(deserializer)?;
<Self as ::std::str::FromStr>::from_str(&raw).map_err(::serde::de::Error::custom)
}
}
};
}
pub(crate) use rule_ids;