Macro mycelium_bitfield::enum_from_bits
source · macro_rules! enum_from_bits { ( $(#[$meta:meta])* $vis:vis enum $Type:ident<$uN:ident> { $(#[$var1_meta:meta])* $Variant1:ident = $value1:expr, $( $(#[$var_meta:meta])* $Variant:ident = $value:expr ),* $(,)? } ) => { ... }; (@bigger u8, $Type:ty) => { ... }; (@bigger u16, $Type:ty) => { ... }; (@bigger u32, $Type:ty) => { ... }; (@bigger u64, $Type:ty) => { ... }; (@bigger $uN:ty, $Type:ty) => { ... }; (@impl $uN:ty, $Type:ty, $($bigger:ty),+) => { ... }; }
Expand description
Generates automatic FromBits
and core::convert::TryFrom
implementations for an enum
type of repr(uN)
, where uN
is one of
u8
, u16
, u32
, u64
, or u128
.
This allows an enum
type to be used with the
bitfield!
macro without requiring a manual FromBits
implementation. Essentially, this macro can be thought of as being analogous
to #[derive(FromBits, TryFrom)]
.1
Generated Implementations
This macro will automatically generate a FromBits
<uN>
and a
core::convert::TryFrom
<uN>
implementation for the defined enum
type.
In addition, FromBits
and core::convert::TryFrom
implementations for
each unsized integer type larger than uN
are also automatically
generated. The Copy
and Clone
traits are also derived for the
generated enum
, as they are required by the FromBits
implementation..
Generated enum
types are [repr(uN)]
].
Additional traits may be derived for the enum
type, such as
PartialEq
, Eq
, and Default
. These traits are not automatically
derived, as custom implementations may also be desired, depending on the
use-case. For example, the Default
value for am enum
may not be all
zeroes.
Examples
Basic usage:
use mycelium_bitfield::FromBits;
use core::convert::TryFrom;
mycelium_bitfield::enum_from_bits! {
/// Doc comments can be added to generated enum types.
#[derive(Debug, PartialEq, Eq)] // additional `derive` attributes can be added
enum Example<u8> { // generate an enum represented by a u8
Foo = 0b0000,
Bar = 0b0001,
Baz = 0b1000,
Qux = 0b0111,
}
}
// the generated enum will implement the `FromBits` trait:
assert_eq!(Example::try_from_bits(0b1u8), Ok(Example::Bar));
assert_eq!(FromBits::<u8>::into_bits(Example::Foo), 0);
// `core::convert::TryFrom` implementations are also generated:
assert_eq!(Example::try_from(0b1000u8), Ok(Example::Baz));
assert_eq!(0b0111u32.try_into(), Ok(Example::Qux));
// invalid bit-patterns return an error:
assert!(Example::try_from_bits(0b1001u8).is_err()); // invalid bit pattern
assert!(Example::try_from_bits(0b1000_0000u8).is_err()); // too many bits
Only u8
, u16
, u32
, u64
, and u128
may be used as repr
s for
generated enums:
mycelium_bitfield::enum_from_bits! {
/// This won't work. Don't do this.
enum InvalidRepr<i32> {
This = 0b01,
Wont = 0b10,
Work = 0b11,
}
}
Why Not
#[derive(FromBits)]
? Some readers may be curious about why this is a declarative macro, rather than a procedural#[derive]
macro. The answer is…“because I felt like it lol”. This probably should be a proc-macro, since it’s essentially just deriving a trait implementation. However, one of my goals formycelium-bitfield
was to see how far I could go using onlymacro_rules!
macros. This isn’t because I dislike procedural macros, or that I’m concerned about proc-macro compile times — I just thought it would be a fun challenge to do everything declaratively, if it was possible. And, if you do care about the potential build time impact of proc-macro dependencies, this should help. :) ↩