Enums under the hood

I'm going through the book and I'm trying to figure out how enums work under the hood. Say a function returns Option<i32> (defined as enum Option<T> {Some(T),None}). What would the runtime datastructure look like? The book refers to enums as tagged unions so if I were to write an equivalent in C, my guess is it would look something like this?

typedef enum {Option_Some, Option_None } OptionTag;
sruct Optioni32 {
    OptionTag tag;
    union {
        int32_t Some;
        // no data for None
    } data;

So then a match like this:

match option {
  Some(x) => /* use x to access the value*/,
  None => /* option does not have a value*/,

would look something like this in C:

if(option.tag == Option_Some) {
  int32_t x = option.data.Some;
  /* use x to access the value */
} else {
  /* option does not have a value */

Am I on the right track or is it implemented another way?

Yes, that's basically it. There are a few special cases to reduce memory usage for constructs like Option<&i32>.

1 Like

This is how its implemented, barring optimizations. There is a guaranteed optimization, called the null pointer optimization for Option and certain types (particularly references) that they will be represented as a pointer without a tag, with None as the null pointer.

1 Like

I was also looking recently to understand how tags are placed. I found it in fn represent_type_uncached here.

1 Like