macro_rules! impl_enum {
(
$(#[$outer:meta])*
$vis:vis enum $name:ident {
$(
$(#[$inner:meta])*
$variant:ident => ($($str:expr),+)
),* $(,)?
}
) => {
$(#[$outer])*
$vis enum $name {
$(
$(#[$inner])*
$variant
),*
}
static INDEX_TO_NAME: &[(&str, &str)] = &[
$(impl_enum!(@tuple $($str),+,)),*
];
static NAME_TO_INDEX: ::phf::Map<&'static str, $name> = ::phf::phf_map! {
$($($str => $name::$variant),+),*
};
impl $name {
pub fn index(name: &str) -> usize {
name.parse::<Self>().expect("provided string did not match any capability") as _
}
#[inline]
pub fn to_index(self) -> usize {
self as _
}
}
impl ::std::fmt::Display for $name {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
let n = if f.alternate() {
INDEX_TO_NAME[*self as usize].1
} else {
INDEX_TO_NAME[*self as usize].0
};
n.fmt(f)
}
}
impl ::std::str::FromStr for $name {
type Err = $crate::index::ParseCapabilityError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
NAME_TO_INDEX
.get(s)
.copied()
.ok_or($crate::index::ParseCapabilityError)
}
}
impl TryFrom<usize> for $name {
type Error = $crate::index::IndexOutOfRangeError;
fn try_from(value: usize) -> Result<Self, Self::Error> {
if value < INDEX_TO_NAME.len() {
Ok(unsafe { ::std::mem::transmute(value) })
} else {
Err($crate::index::IndexOutOfRangeError)
}
}
}
impl From<$name> for usize {
#[inline]
fn from(value: $name) -> Self {
value as usize
}
}
};
(@tuple $first:expr, $second:expr, $($rest:tt)*) => { ($first, $second) };
(@tuple $first:expr, $($rest:tt)*) => { ($first, $first) };
}