Things Zig comptime Won't Do

However, it is impossible to add methods to generated types, they must be inert bundles of fields.

I’ve never tried doing this with methods, but it seems like I can gather arbitrary sets of fields on a type. I recently did this in my new windowing project zin:

pub fn Callback(window_config: WindowConfig) type {
    return makeTaggedUnion(
        &([_]Field{
            .{ .name = "close", .type = void },
            .{ .name = "draw", .type = Draw(window_config) },
        } ++ (if (window_config.data().key_events) [_]Field{
            .{ .name = "key", .type = Key },
        } else [_]Field{}) ++ (if (window_config.data().mouse_events) [_]Field{
            .{ .name = "mouse", .type = Mouse },
        } else [_]Field{}) ++ (if (window_config.data().timers) [_]Field{
            .{ .name = "timer", .type = usize },
        } else [_]Field{})),
    );
}

This code generates a tagged union that looks like this:

const Callback = union(enum) {
    // only include this if app wants mouse events
    mouse: Mouse,
    // only include this if app wants key events
    key: Key,
    // etc...
};

Couldn’t I use a similar technique to create a type and filter on decls?

P.S. here’s the makeTaggedUnion function:

const Field = struct {
    name: [:0]const u8,
    type: type,
};
fn makeTaggedUnion(fields: []const Field) type {
    const EnumField = std.builtin.Type.EnumField;
    const UnionField = std.builtin.Type.UnionField;

    var enum_fields: [fields.len]EnumField = undefined;
    var union_fields: [fields.len]UnionField = undefined;

    for (fields, 0..) |field, i| {
        enum_fields[i] = .{ .name = field.name, .value = i };
        union_fields[i] = .{ .name = field.name, .type = field.type, .alignment = @alignOf(field.type) };
    }

    return @Type(std.builtin.Type{
        .@"union" = .{
            .layout = .auto,
            .tag_type = @Type(std.builtin.Type{ .@"enum" = .{
                .tag_type = std.math.IntFittingRange(0, fields.len - 1),
                .fields = &enum_fields,
                .decls = &.{},
                .is_exhaustive = true,
            } }),
            .fields = &union_fields,
            .decls = &.{},
        },
    });
}