macro_rules! enumerate {
($(#[$enum_attr:meta])* $visibility:vis enum $name:ident ($t:ident) $($(#[$attr:meta])* $variant:ident $(,)? $(;)?)*) => { ... };
($(#[$enum_attr:meta])* $visibility:vis $name:ident ($t:ident) $($(#[$attr:meta])* $variant:ident $(,)? $(;)?)*) => { ... };
($(#[$enum_attr:meta])* $visibility:vis enum $name:ident ($t:ident; $associated_value_type:ty $(= $default_value:expr)?) $($(#[$attr:meta])* $variant:ident $(= $associated_value:expr)? $(,)? $(;)?)*) => { ... };
($(#[$enum_attr:meta])* $visibility:vis one-way enum $name:ident ($t:ident; $associated_value_type:ty $(= $default_value:expr)?) $($(#[$attr:meta])* $variant:ident $(= $associated_value:expr)? $(,)? $(;)?)*) => { ... };
($(#[$enum_attr:meta])* $visibility:vis enum $name:ident ($t:ident; $value_alias:ident : $associated_value_type:ty $(= $default_value:expr)?) $($(#[$attr:meta])* $variant:ident $(= $associated_value:expr)? $(,)? $(;)?)*) => { ... };
($(#[$enum_attr:meta])* $visibility:vis one-way enum $name:ident ($t:ident; $value_alias:ident : $associated_value_type:ty $(= $default_value:expr)?) $($(#[$attr:meta])* $variant:ident $(= $associated_value:expr)? $(,)? $(;)?)*) => { ... };
($(#[$enum_attr:meta])* $visibility:vis one-way $name:ident ($t:ident; $value_alias:ident : $associated_value_type:ty $(= $default_value:expr)?) $($(#[$attr:meta])* $variant:ident $(= $associated_value:expr)? $(,)? $(;)?)*) => { ... };
($(#[$enum_attr:meta])* $visibility:vis one-way $name:ident ($t:ident; $associated_value_type:ty $(= $default_value:expr)?) $($(#[$attr:meta])* $variant:ident $(= $associated_value:expr)? $(,)? $(;)?)*) => { ... };
($(#[$enum_attr:meta])* $visibility:vis $name:ident ($t:ident; $associated_value_type:ty $(= $default_value:expr)?) $($(#[$attr:meta])* $variant:ident $(= $associated_value:expr)? $(,)? $(;)?)*) => { ... };
($(#[$enum_attr:meta])* $visibility:vis $name:ident ($t:ident; $value_alias:ident : $associated_value_type:ty $(= $default_value:expr)?) $($(#[$attr:meta])* $variant:ident $(= $associated_value:expr)? $(,)? $(;)?)*) => { ... };
}
Expand description
This macro helps to create enum with trait Enumeration
.
§Syntax
<code>
means optional
enumerate! {
<#[attribute] ... #[attribute]>
<pub> <one-way> <enum> EnumName(EnumType <; <AssociatedValueAlias> AssociatedType <= DefaultValue>>)
<#[attribute] ... #[attribute]>
Variant1 <= Value> <,> <;>
<#[attribute] ... #[attribute]>
Variant2 <= Value> <,> <;>
...
<#[attribute] ... #[attribute]>
VariantN <= Value> <,> <;>
}
Arguments (in order)
- attributes of the enum (optional)
- a visibility qualifier (optional)
- one-way keyword to disable implementation of
FromValue
(optional) - a name for the enum
- an integer type as the underlying type
- a type for associated constant values (optional)
- an alias for the name of the association (before the type) (optional)
- a default value for associated constant values (optional)
- at least a variant
- attributes (before variant) (optional)
- with associated constant value (only if the associated type is given) (optional only if default is given)
Notes:
- Commas after each variant is not required but accepted by the macro (semicolons are also accepted).
- Keyword
enum
is optional but suggested byofficial Rust syntax guidelines
enumerate! {
pub enum Foo(u8)
Bar, // comma is optional
Baz; // semicolon works too!
}
enumerate! {
FooBar(u8; char)
BarBar = 'a'
BazBar = 'b'
}
enumerate! {
#[doc="foobaz"]
pub FooBaz(u8; &'static str = "default string")
#[doc="barbaz"]
BarBaz = "hello world"
BazBaz // value not provided will be default value
}
§Expanded macro
enumerate! {
pub Foo(u8)
Bar
Baz
}
produces
pub enum Foo {
Bar,
Baz,
}
with implementation of Enumeration
and some other useful traits.
§Casting between index and enumeration
enumerate! {
Foo(u8)
Bar
Baz
}
assert_eq!(Foo::variant(0), Ok(Foo::Bar));
assert_eq!(Foo::variant(1), Ok(Foo::Baz));
assert_eq!(Foo::Bar.to_index(), 0);
assert_eq!(Foo::Baz.to_index(), 1);
assert!(Foo::variant(2).is_err());
See also Enumeration::variant
, Enumeration::variant_unchecked
, Enumeration::to_index
§Associated constant values
enumerate! {
Foo(u8; i32)
Bar = 10
Baz = 20
}
produces
enum Foo {
Bar,
Baz,
}
impl Enumeration for Foo {
fn value(self) -> &'static i32 {
const Bar: &'static i32 = &10;
const Baz: &'static i32 = &20;
match self {
Foo::Bar => Bar,
Foo::Baz => Baz,
}
}
}
assert_eq!(Foo::Bar.value(), &10);
assert_eq!(Foo::Baz.value(), &20);
See also Enumeration::value
§Default constant value
enumerate! {
Foo(u8; i32 = 20)
Bar
Baz = 10
}
produces
enum Foo {
Bar,
Baz,
}
impl DefaultAssociatedValue for Foo {
const DEFAULT_ASSOCIATED_VALUE: i32 = 20;
}
impl Enumeration for Foo {
fn value(self) -> &'static i32 {
const Bar: &'static i32 = &Self::DEFAULT_ASSOCIATED_VALUE;
const Baz: &'static i32 = &10;
match self {
Foo::Bar => Bar,
Foo::Baz => Baz,
}
}
}
assert_eq!(Foo::Bar.value(), &20);
assert_eq!(Foo::Baz.value(), &10);
The macro will emit error if neither associated constant value nor default constant value is provided.
enumerate! {
Foo(u8; i32)
Bar
Baz = 10
}
Note that any constant expression can be used as an associated constant.
See also DefaultAssociatedValue::DEFAULT_ASSOCIATED_VALUE
§Visibility
enumerate! {
pub Foo(u8)
Bar
}
enumerate! {
Baz(u8)
FooBar
}
§Attributes
Attributes can be attached to enumeration itself, default constant value and each of the variants. It’s mostly useful for documentation.
enumerate! {
#[doc="An enumeration named Foo"]
pub Foo(u8)
#[doc="Bar"]
Bar
#[doc="Baz"]
Baz
}
§Examples
enumerate! {
pub Color(u8; &'static str)
Red = "#FF0000"
Blue = "#0000FF"
Yellow = "#FFFF00"
Cyan = "#00FFFF"
}
enumerate! {
State(u8)
None
Stationary
Moving
}
§Two-way conversion
This macro will implement FromValue
that allows converting Enumeration::AssociatedValueType
back into Enumeration
.
enumerate! {
Enum(u8; char)
Foo = 'a'
Bar = 'b'
Baz = 'c'
}
// will also generate
impl FromValue for Enum {
fn from_value<'a>(value: &'a Self::AssociatedValueType) -> Result<Self, UnknownAssociatedValueError<'a, Self>> {
match value {
&'a' => Ok(Enum::Foo),
&'b' => Ok(Enum::Bar),
&'c' => Ok(Enum::Baz),
_ => Err(UnknownAssociatedValueError(value)),
}
}
fn from_value_unchecked(value: &Self::AssociatedValueType) -> Self {
match value {
&'a' => Enum::Foo,
&'b' => Enum::Bar,
&'c' => Enum::Baz,
_ => unreachable!(),
}
}
}
§Opting out
You may not desire to have a two-way conversions in some cases like function pointers
fn f() {}
enumerate! {
Foo(u8; fn())
Bar = (f as fn())
}
You can opt out of the FromValue
implementation by adding the one-way
keyword
fn f() {}
enumerate! {
one-way Foo(u8; fn())
Bar = (f as fn())
}
More info at Enumeration.
§Alias
You can give the associated value an alias
enumerate! {
Foo(u8; some_alias: char)
Bar = 'a'
Baz = 'b'
}
// the left code and the right code is completely same
assert_eq!(Foo::Bar.value(), Foo::Bar.some_alias());
assert_eq!(Foo::Baz.value(), Foo::Baz.some_alias());