Integer enums extended to support ranges and "other" values?


#1

One issue I’ve had with robust/extensible ffi code is that many APIs return an almost-but-not-quite fixed set of integer codes treated as “enums”. That is, there is a potential for having to handle previously unused/reserved values as a plain numeric error code or whatever, often just for logging or pass-through purposes. This can be represented in Rust as-is, but not efficiently, as additional space is required to discriminate between the fixed set and the unrecognised set. Converting back-and-forth is a pain too.

Similarly, many APIs use sets or ranges of integers. Parsing comes to mind, where lexers often return integer streams that are treated as enums. Matching on these can benefit from compiler-generated code that’s difficult to roll by hand.

What I have seen is that library developers simply use constants everywhere, which is the messy filth I associated with Java and C++, not newer languages with fist-class enums such as C# and Rust.

Has anyone proposed this type of feature in Rust:

// The size of this is always 4 bytes!
#[repr(u32)]
enum ApiStatus {
    Success = 0,
    ErrorFoo = 1,
    ErrorBar = 2,
    Warnings = 3..100, // Ranges of values
    Info = ( 200, 210, 211 ), // Discontinuous sets
    Unknown = _ // optionally "everything else"
}

When constructing such an enum, any variant with multiple possible values would have to have the underlying value passed in during construction, or cast from the underlying integer type using the as keyword. E.g.:

let status = 210 as ApiStatus; // one of the three "Info" messages

Thoughts?


#2

It shows a common need, it’s a nice idea that I’d like in Rust. I think this feature is better than what they have in Ada language.

This feature is not meant to replace ranged integral values, because you don’t perform numerical operations on enums:

type Month = u8[1 ... 12];

Better to minimize the use of “as” in Rust code. So better to use try_* functions.