Idiomatic way to convert enum variants into a list

I have an enum, say

pub const Severity = enum {
    low,
    medium,
    high
};

I get a command line string input and parse to this enum.

In case when the input string cannot be parsed, I want to display an error message that lists the enum variants as the accepted inputs.

But I do not want to handcode the variants as string, instead I would like to generate the list of acceptable input string from the enum.

What is the idiomatic way to go about this in Zig? such that I can easily have error message like this

"Error supported input are low, medium, high"

@typeInfo returns an enum describing any zig type.
Using inline for you can concatenate the enum field names. In the following example I just print the names.

const std = @import("std");

pub const Severity = enum {
    low,
    medium,
    high,
};

pub fn main() void {
    inline for (@typeInfo(Severity).Enum.fields) |field| {
        std.debug.print("{s}\n", .{field.name});
    }
}
1 Like

Or, if you need an array of fleld names:

const names = std.meta.fieldNames(Severity);
2 Likes

UPD: made it more generic.
Something like this:

const std = @import("std");

fn enumToErrorMessage(comptime E: type) []const u8 {
    return comptime blk: {
        var msg: []const u8 = "error: supported " ++ @typeName(E) ++ " values are ";
        const field_names = std.meta.fieldNames(E);
        for (field_names, 0..) |field_name, i| {
            msg = msg ++ field_name;
            if (i < field_names.len - 1) {
                msg = msg ++ ", ";
            }
        }
        msg = msg ++ "\n";
        break :blk msg;
    };
}

const Severity = enum {
    low,
    medium,
    high,
};

pub fn main() !void {
    const input_reader = std.io.getStdIn().reader();
    const error_writer = std.io.getStdErr().writer();

    var input_buf: [8]u8 = undefined;
    const input = try input_reader.readUntilDelimiterOrEof(input_buf[0..], '\n');
    if (std.meta.stringToEnum(Severity, input.?)) |severity| {
        std.debug.print("{}\n", .{severity});
    } else {
        try error_writer.writeAll(enumToErrorMessage(Severity));
    }
}
5 Likes

I’d suggest looking into std.enums, it has several data structures which may fit your needs. To map from an enum variant to its name at runtime, your best bet is to construct a StaticStringMap with initComptime. If all you’re interested in is a comma-separated string containing the names of all the variants, you can construct that as well using something like an inline for loop in a comptime block.

1 Like