Pre-RFC enum from integer

Sure, there’s enum_primitive using macros 1.0, and enum-primitive-derive and num-derive using custom derive – all targeting FromPrimitive. I’m sure TryFrom could be derived the same way, although automatically writing this for just the repr type is harder, since we don’t have that type info AFAIK.

Proposed solution:

#[repr(C)]
enum Foo {
  Bar = 0,
  Baz = 1,
  Other(i32),
}

Where Other(i32) is virtual field only allowed for repr(C) enums, which represents other possible variants for enum, like in C.

Here’s an idea:

unsafe trait CEnum {
  type Underlying: Copy;
}
// mod std::intrinsics
fn from_discriminant<E: CEnum>(val: E::Underlying) -> Option<E> { /* filled in by compiler */ }

CEnum is automatically implemented for #[repr(uN)] or #[repr(C)] enums, in “the way one expects”. The intrinsic function does what it says on the tin: eats a number and returns the corresponding variant, if it exists. The actual lookup table for whether an enum is in range is only created when from_discriminant is monomorphized.

I put together https://crates.io/crates/num_enum which allows you to derive TryFrom just for the repr type (by deriving TryFromPrimitive). It also allows you to derive a TryInto implementation which works on stable (by deriving CustomTryInto) because TryFrom isn’t stable yet, but it’s a little ugly/hacky. It was actually refreshingly simple to put together (and my first proc_macro)!

It currently doesn’t allow deriving #[repr(C)] enums because the target size isn’t well-specified.

I’m very open to feedback/improvements, if anyone’s interested.

2 Likes

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.