Derive Macro ConstEach

Source
#[derive(ConstEach)]
{
    // Attributes available to this derive:
    #[value]
    #[armtype]
}
Expand description

Add’s constants of any type to each arm of an enum

To get the value, the type must be explicitly passed as a generic to [<enum_name>::value]. This will automatically try to convert constant to the expected type using std::any::Any and [downcast_ref]. Currently TryFrom is not supported, so typing is fairly strict. Upon failure, it will return None.

  • To get the value as a reference, call the function [<enum_name>::value]
  • Unlike Const, this macro does not enable direct comparison using PartialEq when imported using the eq feature.

The #[armtype = ...] attribute is NOT* required for this macro to function, but *CAN be applied to each individual arm of the enum, since values are not expected to share a type. If no type is given, then the type is inferred from the literal value in the #[value = ...] attribute.

All values set will return a [Option<&'static T>] reference. To the input type, of [T] AND [&T]. If multiple references are used (e.g. &&T), then the return type will be [Option<&'static &T>].

§Example

use thisenum::ConstEach;
 
#[derive(ConstEach, Debug)]
enum MyEnum {
    #[armtype(u8)]
    #[value = 0xAA]
    A,
    #[value = "test3"]
    B,
}
 
#[derive(ConstEach, Debug)]
enum Tags {
    #[value = b"\x00\x01"]
    Key,
    #[armtype(u16)]
    #[value = 24250]
    Length,
    #[armtype(&[u8])]
    #[value = b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"]
    Data,
}
 
fn main() {
    // [`ConstEach`] examples
    assert!(MyEnum::A.value::<u8>().is_some());
    assert!(MyEnum::A.value::<Vec<f32>>().is_none());
    assert!(MyEnum::B.value::<u8>().is_none());
    assert!(MyEnum::B.value::<&str>().is_some());
    assert!(Tags::Data.value::<&[u8]>().is_some());
 
    // An infered type. This will be as strict as possible,
    // therefore [`&[u8]`] will fail but [`&[u8; 2]`] will succeed
    assert!(Tags::Key.value::<&[u8; 2]>().is_some());
    assert!(Tags::Key.value::<&[u8; 5]>().is_none());
    assert!(Tags::Key.value::<&[u8]>().is_none());
    assert!(u16::from_le_bytes(**Tags::Key.value::<&[u8; 2]>().unwrap()) == 0x0100);
 
    // casting as anything other than the defined / inferred type will
    // fail, since this uses [`downcast_ref`] from [`std::any::Any`]
    assert!(Tags::Length.value::<u16>().is_some());
    assert!(Tags::Length.value::<u32>().is_none());
    assert!(Tags::Length.value::<u64>().is_none());
 
    // however, can always convert to a different type
    // after value is successfully acquired
    assert!(*Tags::Length.value::<u16>().unwrap() as u32 == 24250);
}