# Pre-RFC enum from integer

**URL:** <https://internals.rust-lang.org/t/pre-rfc-enum-from-integer/6348>\
**Category:** language design\
**Created:** [December 6, 2017, 6:41pm UTC](https://internals.rust-lang.org/t/pre-rfc-enum-from-integer/6348 "2017-12-06T18:41:13Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![kornel](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kornel/32/2711_2.png) [@kornel](https://internals.rust-lang.org/u/kornel)\
**Post date:** [December 6, 2017, 6:41pm UTC](https://internals.rust-lang.org/t/pre-rfc-enum-from-integer/6348/1 "2017-12-06T18:41:13Z")

</div>

From my perspective (which may be colored by interacting with C a lot) conversion of integers to (field-less) enums is a frequent operation.

Rust has a built-in way to convert an enum to an integer, but not the other way. The current workarounds are pretty bad IMHO:

- Write a `match` for mapping every integer to every variant. This is unacceptably tedious, and the need to manually copy integers leaves room for errors.

- [Use _two_ crates and a macro derive](https://crates.io/crates/enum-primitive-derive). I’m generally OK with using dependencies for small things, but that is such an overkill to merely check whether an integer is in range.

- `mem::transmute()`. I’ve used it, because that is the only one-liner available in Rust, and it has backfired terribly by causing undefined behavior and memory corruption elsewhere in the program.

I wonder if many people will make the same mistake with `transmute`, because especially with `#[repr(C)]` it feels like a harmless no-op integer cast, and not a program-destroying nasal demon.

Since there isn’t a clearly good solution to this problem, Googling for solutions also brings poor results. Depending on how you phrase it you may find old Rust book about enums (which does not contain any solution), GitHub issues about now-dead `FromPrimitive`, and some forum threads which suggest `transmute` or look outdated.

So I think Rust should have a single good solution for making a field-less enum from an integer.

---

<div class="post-metadata">

**Author:** ![cuviper](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cuviper/32/1897_2.png) [@cuviper](https://internals.rust-lang.org/u/cuviper)\
**Post date:** [December 6, 2017, 6:54pm UTC](https://internals.rust-lang.org/t/pre-rfc-enum-from-integer/6348/2 "2017-12-06T18:54:17Z")

</div>

Maybe we can add `#[derive(TryFrom)]` for enums? And I suggest this not try to cover all integer types, just whatever the enum’s `repr` is.

---

<div class="post-metadata">

**Author:** ![leonardo](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/leonardo/32/1344_2.png) [@leonardo](https://internals.rust-lang.org/u/leonardo)\
**Post date:** [December 7, 2017, 12:31am UTC](https://internals.rust-lang.org/t/pre-rfc-enum-from-integer/6348/3 "2017-12-07T00:31:20Z")

</div>

> [@kornel](#):
>
> Rust has a built-in way to convert an enum to an integer,

Do you mean this way?

```
#![allow(dead_code)]

#[repr(u32)]
enum Foo { A = 300, B = 500 }

fn main() {
    let a: u8 = Foo::A as u8;
    println!("{}", a);
}

```

It's not good enough, as you see it could lead to bugs.

---

<div class="post-metadata">

**Author:** ![kornel](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kornel/32/2711_2.png) [@kornel](https://internals.rust-lang.org/u/kornel)\
**Post date:** [December 7, 2017, 9:33am UTC](https://internals.rust-lang.org/t/pre-rfc-enum-from-integer/6348/4 "2017-12-07T09:33:54Z")

</div>

Yeah, the `as` operator is pretty bad in general, but at least there’s a way.

I suppose TryFrom could also add implementation from enum to int (with Error=!), but I wouldn’t mind if that was out of scope for this proposal and left to be fixed as part of fixing of the `as` operator.

---

<div class="post-metadata">

**Author:** ![lacourc](https://avatars.discourse-cdn.com/v4/letter/l/4da419/32.png) [@lacourc](https://internals.rust-lang.org/u/lacourc)\
**Post date:** [December 7, 2017, 5:23pm UTC](https://internals.rust-lang.org/t/pre-rfc-enum-from-integer/6348/5 "2017-12-07T17:23:18Z")

</div>

> [@cuviper](#):
>
> Maybe we can add #[derive(TryFrom)] for enums? And I suggest this not try to cover all integer types, just whatever the enum’s repr is.

I ran into the same problem as @kornel already and I would love to see this implemented.

---

<div class="post-metadata">

**Author:** ![zackw](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/zackw/32/2071_2.png) [@zackw](https://internals.rust-lang.org/u/zackw)\
**Post date:** [December 7, 2017, 9:43pm UTC](https://internals.rust-lang.org/t/pre-rfc-enum-from-integer/6348/6 "2017-12-07T21:43:31Z")

</div>

Please think about bit-flag enumerations when designing this. Bit-flag enumerations have some constants given explicit names and values with disjoint bit patterns, and then programs may use the logical OR of any set of the named constants, possibly with some exceptions (which, of course, C does not check for). They are very common in C low-level interfaces, for instance the second argument to the POSIX [open](http://pubs.opengroup.org/onlinepubs/9699919799/functions/open.html) primitive on Linux can be any combination of

```rust
enum OpenFlags {
  O_RDONLY = 0x00000000,
  O_WRONLY = 0x00000001,
  O_RDWR = 0x00000002,
  O_ACCMODE = 0x00000003,
  O_CREAT = 0x00000040,
  O_EXCL = 0x00000080,
  O_NOCTTY = 0x00000100,
  O_TRUNC = 0x00000200,
  O_APPEND = 0x00000400,
  O_NONBLOCK = 0x00000800,
  O_DSYNC = 0x00001000,
  O_ASYNC = 0x00002000,
  O_DIRECT = 0x00004000,
  O_LARGEFILE = 0x00008000,
  O_DIRECTORY = 0x00010000,
  O_NOFOLLOW = 0x00020000,
  O_NOATIME = 0x00040000,
  O_CLOEXEC = 0x00080000,
  O_SYNC = 0x00101000,
  O_PATH = 0x00200000,
  O_TMPFILE = 0x00410000,
  O_NDELAY = O_NONBLOCK,
  O_FSYNC = O_SYNC
}

```

except that you must use exactly one of `O_RDONLY`, `O_WRONLY`, and `O_RDWR`, and some of the combinations of the others might not make a whole lot of sense.

Rust’s insistence that variables with a numeric-enum type can only have values equal to one of the named constants means that this kind of foreign interface is poorly handled.

---

<div class="post-metadata">

**Author:** ![kornel](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kornel/32/2711_2.png) [@kornel](https://internals.rust-lang.org/u/kornel)\
**Post date:** [December 7, 2017, 9:54pm UTC](https://internals.rust-lang.org/t/pre-rfc-enum-from-integer/6348/7 "2017-12-07T21:54:09Z")

</div>

isn’t bitflags crate solving this sufficiently well?

---

<div class="post-metadata">

**Author:** ![leonardo](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/leonardo/32/1344_2.png) [@leonardo](https://internals.rust-lang.org/u/leonardo)\
**Post date:** [December 7, 2017, 10:32pm UTC](https://internals.rust-lang.org/t/pre-rfc-enum-from-integer/6348/8 "2017-12-07T22:32:14Z")

</div>

> [@zackw](#):
>
> Rust’s insistence that variables with a numeric-enum type can only have values equal to one of the named constants means that this kind of foreign interface is poorly handled.

C conflates two different purposes, the enumeration and the bitwaise flags, they have different semantics and different purposes. One can argue that a system language should support both with a different syntax (or using an external crate).

---

<div class="post-metadata">

**Author:** ![ratmice](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ratmice/32/4917_2.png) [@ratmice](https://internals.rust-lang.org/u/ratmice)\
**Post date:** [December 7, 2017, 11:23pm UTC](https://internals.rust-lang.org/t/pre-rfc-enum-from-integer/6348/9 "2017-12-07T23:23:43Z")

</div>

Also worth noting the [enumflags](https://crates.io/crates/enumflags) crate

---

<div class="post-metadata">

**Author:** ![zackw](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/zackw/32/2071_2.png) [@zackw](https://internals.rust-lang.org/u/zackw)\
**Post date:** [December 12, 2017, 2:20am UTC](https://internals.rust-lang.org/t/pre-rfc-enum-from-integer/6348/10 "2017-12-12T02:20:14Z")

</div>

I feel like anything that the libc crate needs to do its job thoroughly should be in std.

(I should probably say that I’ve spent 95% of my professional coding time for years in Python, where “the batteries are included” is a watchword for the stdlib, and that’s trained me to find it irritating whenever I have to reach for a third-party library/crate.)

---

<div class="post-metadata">

**Author:** ![jan\_hudec](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jan_hudec/32/4100_2.png) [@jan\_hudec](https://internals.rust-lang.org/u/jan_hudec)\
**Post date:** [December 14, 2017, 5:12pm UTC](https://internals.rust-lang.org/t/pre-rfc-enum-from-integer/6348/11 "2017-12-14T17:12:15Z")

</div>

> [@zackw](#):
>
> bit-flag enumerations […] They are very common in C low-level interfaces

No, they are not, because they are just as illegal in C as they are in Rust. In fact while Rust insists an enum may only have one of the defined values, C and C++ may _silently assume it_.

> [@zackw](#):
>
> for instance the second argument to the POSIX open

> [@IEEE Std 1003.1-2008](#):
>
> `int open(const char *path, int oflag, ...);`

See the type? It is `int`. _Not_ an `enum`. It can't be, because even if the original constants were defined as enums—which they are not, `asm-generic/fcntl.h` defines them as macros—there is no `|` operator for enum types, so they get implicitly converted to `int` and the result of `|` is always `int`.

In C, flags are always (`short`/`long`/`unsigned`) `int`. C++ sometimes creates custom classes for them, e.g. the [`std::ios_base::openmode`](http://en.cppreference.com/w/cpp/io/ios_base/openmode) (there are a few more in `ios_base`). The same should be done in Rust—and that's what the [bitflags](https://crates.io/crates/bitflags) and [enumflags](https://crates.io/crates/enumflags) crates are for.

In C and C++, `enum` is sometimes used just to define the constants—because `const` may still be given memory and `#define`s are not scoped, so before `constexpr` `enum` was preferred way of defining compile-time constants that are guaranteed to be inlined. But usually in the anonymous form.

> [@zackw](#):
>
> I feel like anything that the libc crate needs to do its job thoroughly should be in std.

I think it would make sense to coopt something like this in the standard library once the preferred design is clear. However, since they are not—and cannot—be based on actual `enum`s, it is completely orthogonal to the thing in the original post.

> [@ratmice](#):
>
> Also worth noting the enumflags crate

I actually think that one is a bad idea. Basing a flags type on an enum does not really make sense.

---

<div class="post-metadata">

**Author:** ![zackw](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/zackw/32/2071_2.png) [@zackw](https://internals.rust-lang.org/u/zackw)\
**Post date:** [December 14, 2017, 7:26pm UTC](https://internals.rust-lang.org/t/pre-rfc-enum-from-integer/6348/12 "2017-12-14T19:26:41Z")

</div>

> [@jan\_hudec](#):
>
> > bit-flag enumerations […] They are very common in C low-level interfaces
> 
> No, they are not, because they are just as illegal in C as they are in Rust. In fact while Rust insists an enum may only have one of the defined values, C and C++ may silently assume it.

Who told you that? That's not true at all. A variable with `enum` type in C can legitimately hold any value that is valid for the "underlying type" of the enumeration. This is not explicitly stated in the standard, but follows from the rule that each enumerated type is _compatible_ with some integer type (N1570 §6.7.2.2p4) and the explicit license to type-pun as long as the two types are compatible (6.5p7).

---

<div class="post-metadata">

**Author:** ![jan\_hudec](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jan_hudec/32/4100_2.png) [@jan\_hudec](https://internals.rust-lang.org/u/jan_hudec)\
**Post date:** [December 14, 2017, 8:23pm UTC](https://internals.rust-lang.org/t/pre-rfc-enum-from-integer/6348/13 "2017-12-14T20:23:23Z")

</div>

Ok, you are right. And actually it _is_ explicitly stated in the (at least the C++) specification, because it says cast maintains value as long as it is within the range and the range is defined so that it is the underlying type if fixed and _closed to `|` over the declared enumerators otherwise_ (the wording is completely different, but that’s the effect).

Still, because C++ converts enums to the underlying type implicitly, but _not_ the other way around, the usual approach is to use `enum` to define the flags, but pass them around as integer—or special type as the iostreams library does.

However, for Rust, this kind of use is incompatible with the `match` logic, so for Rust using `enum` is not appropriate. The custom structs are.

---

<div class="post-metadata">

**Author:** ![ratmice](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ratmice/32/4917_2.png) [@ratmice](https://internals.rust-lang.org/u/ratmice)\
**Post date:** [December 14, 2017, 9:39pm UTC](https://internals.rust-lang.org/t/pre-rfc-enum-from-integer/6348/14 "2017-12-14T21:39:30Z")

</div>

> [@jan\_hudec](#):
>
> However, for Rust, this kind of use is incompatible with the match logic, so for Rust using enum is not appropriate. The custom structs are.

This is certainly a stance I can sympathize with, my own opinion would be that this is a limitation of the match logic, which could be extended to abstract data types using something like views

> **[views.pdf](https://www.cs.tufts.edu/~nr/cs257/archive/chris-okasaki/views.pdf)**
>
> 198.97 KB

making the integer representation abstract but allowing one to still match on it. but that is probably a different discussion

---

<div class="post-metadata">

**Author:** ![kornel](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kornel/32/2711_2.png) [@kornel](https://internals.rust-lang.org/u/kornel)\
**Post date:** [December 14, 2017, 10:00pm UTC](https://internals.rust-lang.org/t/pre-rfc-enum-from-integer/6348/15 "2017-12-14T22:00:03Z")

</div>

In case of Rust it’s clear that enum can hold strictly only one of its variants, and anything else leads to undefined behaviour. And it’s not even theoretical problem. Since the latest enum optimisations have landed it actually causes memory corruption if you force enum to hold another value.

---

<div class="post-metadata">

**Author:** ![cardoe](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cardoe/32/4054_2.png) [@cardoe](https://internals.rust-lang.org/u/cardoe)\
**Post date:** [December 16, 2017, 7:35pm UTC](https://internals.rust-lang.org/t/pre-rfc-enum-from-integer/6348/16 "2017-12-16T19:35:47Z")

</div>

Hi,

Author of [enum-primitive-derive](https://crates.io/crates/enum-primitive-derive) here. I’d certainly love to improve the usage or make it easier to use the crate as well until there is a solution in the language itself. I wanted to use something that provided by absolute guarantee when creating a FFI so that’s why I made it. The other solutions out there were clunky so I felt a custom derive was the easiest way to go. I couldn’t figure out how to not require two crates since the trait that everyone expects is provided by [num-traits](https://crates.io/crates/num-traits) and cannot be re-exported by a procedural macros crate.

Any suggestions are very much welcome!

---

<div class="post-metadata">

**Author:** ![bascule](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/bascule/32/3057_2.png) [@bascule](https://internals.rust-lang.org/u/bascule)\
**Post date:** [December 16, 2017, 8:50pm UTC](https://internals.rust-lang.org/t/pre-rfc-enum-from-integer/6348/17 "2017-12-16T20:50:34Z")

</div>

On the [Rust issue for C enums and undefined behavior](https://github.com/rust-lang/rust/issues/36927#issuecomment-297481576), I suggested (if it’s possible) to specify a default for `repr(C)` enums in the event they are out of range.

For many of the enums I worked with there was a simple and obvious choice of a default.

Being able to use enums directly in my bindings would massively simplify the bindings in many cases, an opinion that [the creators of bindgen seem to share](https://github.com/rust-lang-nursery/rust-bindgen/issues/667). It would be really nice if there were a good solution here which would enable that safely.

---

<div class="post-metadata">

**Author:** ![mitsuhiko](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/mitsuhiko/32/379_2.png) [@mitsuhiko](https://internals.rust-lang.org/u/mitsuhiko)\
**Post date:** [February 5, 2018, 9:16am UTC](https://internals.rust-lang.org/t/pre-rfc-enum-from-integer/6348/18 "2018-02-05T09:16:59Z")

</div>

I keep running into this issue. I think in an ideal world `TryFrom` could be derived with a `TryFromIntError` as the error case. I also ran into what @bascule mentioned. We have a lot of cbindings for rust crates and there we always have a special value in the enum that acts as a stand-in for unknown values. However I do not think that this default should be an actual `Default`. With `TryFrom` this pattern would work:

```rust
let foo = 42.try_into().unwrap_or(MyEnum::SomeDefault);

```

(In particular I just now came across this issue again because I want to have something like an `AtomicEnum` and that’s pretty tricky to implement currently without some automatic two way conversion to integers)

---

<div class="post-metadata">

**Author:** ![Alfriadox](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/alfriadox/32/11232_2.png) [@Alfriadox](https://internals.rust-lang.org/u/Alfriadox)\
**Post date:** [March 15, 2018, 2:10pm UTC](https://internals.rust-lang.org/t/pre-rfc-enum-from-integer/6348/19 "2018-03-15T14:10:47Z")

</div>

Is this still alive?

---

<div class="post-metadata">

**Author:** ![nikomatsakis](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nikomatsakis/32/5410_2.png) [@nikomatsakis](https://internals.rust-lang.org/u/nikomatsakis)\
**Post date:** [March 16, 2018, 4:08pm UTC](https://internals.rust-lang.org/t/pre-rfc-enum-from-integer/6348/20 "2018-03-16T16:08:18Z")

</div>

It’s still a need =) but I’m not aware of any recent developments here. That said, the fact that custom derive exists seems like it could be used to solve this problem in “user land” quite readily.

[Next page](https://internals.rust-lang.org/t/pre-rfc-enum-from-integer/6348.md?page=2)
