#is it possible to add fields to a enum dynamically?

1 messages ยท Page 1 of 1 (latest)

round folio
#

hi folks, how can i dynamically add fields to a enum?

my usecase is like that:

const Mode = enum {
    x, r, w
};

Mode.rw = .r | .w;
Mode.rwx = .rw | .x;
tawdry narwhal
#

You can use comptime to construct a enum

#

But not at runttime

round folio
#

hi thanks, could you give me an example or a link?

tawdry narwhal
#

Note, is not the same enum

#

give me a sec

round folio
tawdry narwhal
#

Yea

round folio
#

i had wrote it two months ago, and i still have no idea to simplify it, hehe

tawdry narwhal
#

Dunno if this works

#

but

#

something along this lines

#
fn GetEnum(someEnum: type) type {
    var fields: []const std.builtin.Type.EnumField = std.meta.fields(someEnum);
    var counter = fields.len;
    inline for (std.meta.fields(someEnum)) |x, i| {
        inline for (std.meta.fields(someEnum)[i..]) |y, j| {
            fields = fields ++ std.builtin.Type.EnumField{ .name = x.name ++ y.name, .value = counter };
        }
    }
    var enumInfo = @typeInfo(someEnum);
    return @TypeOf(std.builtin.Type.Enum{
        .layout = enumInfo.Enum.layout,
        .tag_type = std.math.IntFittingRange(0, fields.len),
        .fields = fields,
        .decls = &.{},
        .is_exhaustive = true,
    });
}
round folio
#

wow, never thought zig can do like that!

#

thank you for the direction, i will try it.

tawdry narwhal
#

Yeah, the code might be bad btw

#

I am not testing this

#

lol

#

but something along this lines it is

jade fox
#

append line should be fields = fields ++ &[1]std.builtin.Type.EnumField{ .{ .name = ... } } I think? Or can you append a single element like that and I never realised?

tawdry narwhal
#

tho you can do &.{} and using an @as too

#

lol

round folio
#

no worries, the direction is enough for me. i'll learn it by tests

jade fox
#

so figured I'd just annotate on the outside

tawdry narwhal
#

yeah, just saying that &.{} and a @as makes it like that

#

lol

jade fox
#

Oh right yeah

tawdry narwhal
#

@as(your_ptr_type, &.{something});

round folio
#

thank you all!

tawdry narwhal
#

Other error I am seeing now

#

You need to make the union lol

#
@Type(.{ .Enum = std.builtin.Type.Enum{
        .layout = enumInfo.Enum.layout,
        .tag_type = std.math.IntFittingRange(0, fields.len),
        .fields = fields,
        .decls = &.{},
        .is_exhaustive = true,
    } })```
#

and is @Type lol

#

Yeah not sleeping makes me slow

#
fn GetEnum(comptime someEnum: type) type {
    var fields: []const std.builtin.Type.EnumField = std.meta.fields(someEnum);
    var counter = fields.len;
    inline for (std.meta.fields(someEnum)) |x, i| {
        inline for (std.meta.fields(someEnum)[i + 1 ..]) |y| {
            fields = fields ++ @as([]const std.builtin.Type.EnumField, &.{std.builtin.Type.EnumField{ .name = x.name ++ y.name, .value = counter }});
            counter += 1;
        }
    }
    var enumInfo = @typeInfo(someEnum);
    return @Type(.{ .Enum = std.builtin.Type.Enum{
        .layout = enumInfo.Enum.layout,
        .tag_type = std.math.IntFittingRange(0, fields.len),
        .fields = fields,
        .decls = &.{},
        .is_exhaustive = true,
    } });
}

@round folio

#

this works

#

just tested it

#
const SomeEnum = enum {
    a,
    b,
    c,
};
/// Some other will have: a, b, c, ab, ac, bc
const SomeOther = GetEnum(SomeEnum);
round folio
#

yeah, works like a charm.

const Mode = GetEnum(enum { x, r, w });

pub fn main() !void {
    print("{d} {d}", .{ @enumToInt(Mode.x), @enumToInt(Mode.rw) });
}
thick kayak
#

is this not best solved with bitwise flags? If you want to check for r you now have to check against multiple enums

tawdry narwhal
#

Depends on objective

#

You can make this code ignore certain combinations

#

or you can make a enumSet for example

round folio
#

i guess i certainly can do some magic when generating these fields, so it isnt
a problem to this approach

tawdry narwhal
#

std.enums.EnumSet

#

which is backed by a bitfield

thick kayak
#

yeah, but rwx are flags, so why go through all these hoops

tawdry narwhal
thick kayak
#

fair

#

just smelled like xy

tawdry narwhal
#

I think packed structs are better for flags for example

thick kayak
#

yeah those are nice

tawdry narwhal
#

you could use with this now, EnumFieldStruct (std.enums.EnumFieldStruct)

#

Which generates a struct that have booleans for example

thick kayak
#

I think std prefers packed structs for flags in a lot of places now

tawdry narwhal
#

Haven't seen them ๐Ÿ˜›

thick kayak
#

pub const DllFlags = packed struct {

tawdry narwhal
#

Probably on new code

#

Yea

thick kayak
#

stuff like that

tawdry narwhal
#

There are still a bunch of methods that fit better or worse depending on how you wanna present it

thick kayak
#

yeah, just felt wrong to use a bunch metaprogramming enums for this, but dunno the context

tawdry narwhal
#

fair

round folio
signal wraith
#

People in this thread have answered how but never asked why :)

#

In Zig, you'd normally do this differently

#

Instead of a flags enum with r, w, x, rw, etc, you'd use a flags struct

tawdry narwhal
signal wraith
#
const Mode = packed struct {
    read: bool = false,
    write: bool = false,
    execute: bool = false,
};```
tawdry narwhal
#

or you can do it manually

#

both ways are valid

#

and both ways will result in similar code

signal wraith
#

Ah yeah this was discussed, missed that

tawdry narwhal
#

But yes, that's a good example on a packed struct flag

#

which is a bitflag

tawdry narwhal