Crate enum_repr

Source
Expand description

Generate enum repr conversions compatible with type aliases.

Generate with #[EnumRepr(type = "TYPE")].

Functions generated are

fn repr(&self) -> EnumReprType
fn from_repr(x: EnumReprType) -> Option<Self>

The real enum discriminant is usually forced to be #[repr(isize)]. If u* or i* types are used for the discriminant, the actual enum representation is made to be #[repr(that_type_specified)]. The list of types recognized as u* and i* currently is as follows: i8, i16, i32, i64, i128, u8, u16, u32, u64, u128. If the type is specified through a type alias, #[repr(isize)] is used. Inability to specify type aliases as enum representations is this crate’s reason to exist.

The code generated does not require std.

§Examples

extern crate enum_repr;
extern crate libc;

use libc::*;

use enum_repr::EnumRepr;

#[EnumRepr(type = "c_int")]
#[derive(Debug, PartialEq)]
pub enum IpProto {
    IP = IPPROTO_IP,
    IPv6 = IPPROTO_IPV6,
    // …
}

assert_eq!(IpProto::IP.repr(), IPPROTO_IP);
assert_eq!(IpProto::from_repr(IPPROTO_IPV6), Some(IpProto::IPv6));
assert!(IpProto::from_repr(12345).is_none());
#[EnumRepr(type = "c_int")]
pub enum InetDomain {
    Inet = 2,
    // …
}

#[EnumRepr(type = "c_int")]
pub enum SocketType {
    Stream = 1,
    // …
}

// …

unsafe {
    assert!(
       socket(InetDomain::Inet.repr(), SocketType::Stream.repr(), 0) != -1
    );
}
// compatible with documentation and other attributes

/// Represents a layer 3 network protocol.
#[EnumRepr(type = "c_int")]
#[derive(Debug, PartialEq)]
pub enum IpProto {
    IP = IPPROTO_IP,
    IPv6 = IPPROTO_IPV6,
    // …
}

Discriminants can be implicit if implicit = true:


#[EnumRepr(type = "c_int", implicit = true)]
#[derive(Debug, PartialEq)]
pub enum Test {
    A,
    B,
    C = 5,
    D,
}

assert_eq!(Test::B.repr(), 1);
assert_eq!(Test::from_repr(6), Some(Test::D));
assert!(Test::from_repr(2).is_none());

Using implicit discriminants without setting the flag is an error:


#[EnumRepr(type = "c_int")]
pub enum Test {
    A,
    B = 3
}

Take extra care to avoid collisions when using implicit discriminants:

#[EnumRepr(type = "u8", implicit = true)]
enum Test {
    A = 1,
    B,
    C,
    D = 3,
}

Out of bound discriminants fail to compile:

#[EnumRepr(type = "u8")]
enum Test {
    A = 256
}

Even if they are implicit:

#[EnumRepr(type = "u8", implicit = true)]
enum Test {
    A = 255,
    B
}

Discriminants of a wrong type fail to compile as well:

const C: u16 = 256;

#[EnumRepr(type = "u8")]
enum Test {
    A = C
}

Using the actual enum discriminant representation:

#[EnumRepr(type = "u8")]
#[derive(Debug, PartialEq)]
enum Test {
    A = 1
}

assert_eq!(size_of::<u8>(), size_of::<Test>());

Attribute Macros§