#[macro_export]
macro_rules! convertible_enum {
(#[repr($type:ty)]$(#[$meta:meta])* $visibility:vis enum $enum_name:ident {
$($(#[$variant_meta:meta])* $variant_name:ident = $variant_value:expr,)*
}) => {
#[repr($type)]
$(#[$meta])*
$visibility enum $enum_name {
$($(#[$variant_meta])* $variant_name = $variant_value,)*
Unknown($type)
}
impl std::convert::From<$type> for $enum_name {
fn from(v: $type) -> Self {
if false { unreachable!() }
$( else if v == $variant_value { Self::$variant_name } )*
else { Self::Unknown(v) }
}
}
impl std::convert::From<$enum_name> for $type {
fn from(value: $enum_name) -> $type {
match value {
$($enum_name::$variant_name => $variant_value,)*
$enum_name::Unknown(other) => other,
}
}
}
}
}
#[macro_export]
macro_rules! maybe_convertible_enum {
(#[repr($type:ty)]$(#[$meta:meta])* $visibility:vis enum $enum_name:ident {
$($(#[$variant_meta:meta])* $variant_name:ident = $variant_value:expr,)*
}) => {
#[repr($type)]
$(#[$meta])*
$visibility enum $enum_name {
$($(#[$variant_meta])* $variant_name = $variant_value,)*
}
paste::paste! {
#[derive(Debug, PartialEq, Eq)]
pub struct [<Unknown $enum_name ValueError>](pub $type);
impl std::fmt::Display for [<Unknown $enum_name ValueError>] {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, concat!("Enum '", stringify!($enum_name), "' has no variant with value '{}'"), self.0)
}
}
impl std::error::Error for [<Unknown $enum_name ValueError>] {}
impl std::convert::TryFrom<$type> for $enum_name {
type Error = [<Unknown $enum_name ValueError>];
fn try_from(v: $type) -> Result<Self, Self::Error> {
match v {
$($variant_value => Ok(Self::$variant_name),)*
other => Err([<Unknown $enum_name ValueError>](other)),
}
}
}
}
impl From<$enum_name> for $type {
fn from(v: $enum_name) -> $type {
match v {
$($enum_name::$variant_name => $variant_value,)*
}
}
}
}
}
pub use {convertible_enum, maybe_convertible_enum};