Macro enumeraties::props
source · [−]macro_rules! props {
(
// A lazy/const impl that will be promoted to `Deref` (also impls `EnumProp`)
impl Deref for $enum_name:ty as $modifier:ident $prop_name:path { $($matching:tt)* }
) => { ... };
(
// The lazy/const impl via inherent method (also impls `EnumProp`)
impl $enum_name:ty : $fn_vis:vis fn $fn_name:ident as $modifier:ident $prop_name:path { $($matching:tt)* }
) => { ... };
(
// The lazy/const impl `EnumProp` only
impl EnumProp for $enum_name:ty as $modifier:ident $prop_name:path { $($matching:tt)* }
) => { ... };
}
Expand description
Adds a property onto an enum
Const, Static, Lazy
This macro allows implement properties in three different ways:
- as
const
, a constant - as
static
, a global variable - as
lazy
, a lazily initialized static
const
and static
are very similar, but have subtle difference:
the property type put into a static
must implement Send
. However,
with a static
it is guaranteed that for each variant there is exactly one
unique property value and thus a unique reference address.
With const
the compiler is allowed to merge properties (if they are equal)
or to inline and instantiated the same logical property multiple times,
i.e. the same logical property might be accessed via different reference
addresses.
In the very most cases, the actual reference address should not be of any
concern and thus it is recommended to use const
over static
.
One notable use-case for static
is when the property contains interior
mutability.
In these cases, const
shouldn’t even compile.
lazy
, on the other hand, is quite different from the const
and static
.
While const
and static
require constant initialized values computed at
compile-time, lazy
allows to evaluate the value lazily at runtime,
instead. However, this feature incurs some overhead at each access, because
it must be checked that the value was indeed already initialized.
And of course, the first access to a lazy
value, will incur the additional
delay to initialize the value.
Syntax
This macro comes with essentially three different syntaxes: to implement
Deref
(for the primary property), add an inherent access method
(for secondary properties), or just implementing EnumProp
onto it (e.g.,
if only used by generic code).
Implementing Deref
Syntax:
impl Deref for <ENUM> as (const|static|lazy) <PROPERTY> {
<VARIANT> => {
<FIELD> : <VALUE>,
...
},
...
}
Example:
struct Prop { name: &'static str }
enum Foo {A}
props! {
impl Deref for Foo as const Prop {
Self::A => {
name: "Foo",
}
}
}
// Direct access due to deref
assert_eq!(Foo::A.name, "Foo");
Implementing an inherent method
Syntax:
impl <ENUM> : <VIS> fn <FN_NAME> as (const|static|lazy) <PROPERTY> {
<VARIANT> => {
<FIELD> : <VALUE>,
...
},
...
}
Example:
struct Prop { name: &'static str }
enum Foo {A}
props! {
// Of course, an arbitrary function names can be used instead of `getter`
impl Foo : fn getter as const Prop {
Self::A => {
name: "Foo",
}
}
}
// Access via inherent method
assert_eq!(Foo::A.getter().name, "Foo");
Implementing only EnumProp
Syntax:
impl EnumProp for <ENUM> as (const|static|lazy) <PROPERTY> {
<VARIANT> => {
<FIELD> : <VALUE>,
...
},
...
}
Example:
struct Prop { name: &'static str }
enum Foo {A}
props! {
impl EnumProp for Foo as const Prop {
Self::A => {
name: "Foo",
}
}
}
// Access via universal function call
use enumeraties::EnumProp;
assert_eq!(EnumProp::<Prop>::property(&Foo::A).name, "Foo");