const std = @import("std"); /// Maps each field of a struct `S` to the enum value in `E` pub fn StructFieldsMap( comptime S: type, comptime E: type, ) type { const KV = struct { []const u8, E }; var slice: []const KV = &[_]KV{}; var idx: usize = 0; for (std.meta.fields(S)) |field| { slice = slice ++ &[_]KV{.{ field.name, @intToEnum(E, idx) }}; idx += 1; } return std.ComptimeStringMap(E, slice); } /// Creates an enum with fields matching each field in struct `S`. /// Runs `F` for each field in `S` to modify the names in the resulting enum. // sort of opposite to the included EnumFieldStruct in std pub fn StructFieldsEnum( comptime S: type, comptime F: ?fn (comptime []const u8) []const u8, ) type { const EnumField = std.builtin.Type.EnumField; var fields: []const EnumField = &[_]EnumField{}; var idx: usize = 0; for (std.meta.fields(S)) |field| { fields = fields ++ &[_]EnumField{.{ .name = blk: { if (F) |f| break :blk f(field.name); break :blk field.name; }, .value = idx, }}; idx += 1; } return @Type(.{ .Enum = .{ .tag_type = usize, .fields = fields, .decls = &.{}, .is_exhaustive = true, } }); } const TestStruct = struct { a_a: bool, b_b: bool, }; fn replaceUnderscores(comptime o: []const u8) []const u8 { var name: [o.len]u8 = undefined; _ = std.mem.replace(u8, o, &[_]u8{'_'}, &[_]u8{'-'}, &name); return &name; } test "StructFieldsEnum" { { const e = StructFieldsEnum(TestStruct, null); try std.testing.expect(std.mem.eql(u8, std.meta.fields(e)[0].name, "a_a")); try std.testing.expect(std.mem.eql(u8, std.meta.fields(e)[1].name, "b_b")); } { const e = StructFieldsEnum(TestStruct, replaceUnderscores); try std.testing.expect(std.mem.eql(u8, std.meta.fields(e)[0].name, "a-a")); try std.testing.expect(std.mem.eql(u8, std.meta.fields(e)[1].name, "b-b")); } } test "StructFieldsMap" { { const e = StructFieldsEnum(TestStruct, null); const map = StructFieldsMap(TestStruct, e); try std.testing.expect(std.mem.eql(u8, @tagName(map.get("a_a").?), "a_a")); try std.testing.expect(std.mem.eql(u8, @tagName(map.get("b_b").?), "b_b")); } { const e = StructFieldsEnum(TestStruct, replaceUnderscores); const map = StructFieldsMap(TestStruct, e); try std.testing.expect(std.mem.eql(u8, @tagName(map.get("a_a").?), "a-a")); try std.testing.expect(std.mem.eql(u8, @tagName(map.get("b_b").?), "b-b")); } }