#Dynamically add union field type to list

1 messages · Page 1 of 1 (latest)

bitter marsh
#

Crude example:

const std = @import("std");

const Foo = struct {};
const Bar = struct {};

pub const Entity = union(enum) {
    foo: Foo,
    bor: Bar,
};

fn add(map: *std.AutoArrayHashMap(u32, Entity), e: anytype) !void {
    map.put(0, .{ .foo = e });
}

pub fn main() !void {
    var debug = std.heap.DebugAllocator(.{}){};
    defer _ = debug.deinit();
    const alloc = debug.allocator();

    var entities: std.AutoArrayHashMap(u32, Entity) = .init(alloc);
    defer entities.deinit();

    const entity: Foo = .{};
    try add(&entities, entity);
}

I'd like to adapt the add function to take anytype (as a Foo or Bar), and have the function create the respective wrapping of Entity.
I want to do this dynamically, instead of having a switch statement inside add.
Can this be done? I could iterate over Entity to find the field of the matching type, but am not sure how I could generate .{ .foo = e} for example.

delicate nest
#

switch { inline else |ent| => {} } + @tagName + @unionInit

bitter marsh
#

Ah, unionInit is what I was missing. Thank you

#

Ended up doing this:

fn add(map: *std.AutoArrayHashMap(u32, Entity), e: anytype) !void {
    inline for (@typeInfo(Entity).@"union".fields) |f| {
        if (f.type == @TypeOf(e)) {
            return map.put(0, @unionInit(Entity, f.name, e));
        }
    }
    @compileError("Invalid type " ++ @typeName(@TypeOf(e)));
}

Not sure which thing you're doing a switch over, here

#

@delicate nest did you mean something like

fn add2(map: *std.AutoArrayHashMap(u32, Entity), e: anytype) !void {
    switch (std.meta.tags(Entity)) {
        inline else => |ent| {
            return map.put(0, @unionInit(Entity, @tagName(ent), e));
        },
    }
}

Doesn't compile but was trying to follow what you were saying

delicate nest
#

Remove std.meta.tags(Entity) and replace with e. e should be Entity

bitter marsh
#

e is Foo or Bar in this case

#

I forgot to update my first example, I'll fix it now

delicate nest
#

You can iterate over @typeInfo(e).@"union".fields[i].type and match your type to use with @unionInit

#

Still, your use case is weird.