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 bitsOnly u8, u16, u32, u64, and u128 may be used as reprs 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-bitfieldwas 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. :) ↩