diff options
Diffstat (limited to 'src/util')
-rw-r--r-- | src/util/enum.zig | 56 | ||||
-rw-r--r-- | src/util/struct.zig | 85 |
2 files changed, 141 insertions, 0 deletions
diff --git a/src/util/enum.zig b/src/util/enum.zig new file mode 100644 index 0000000..216d04e --- /dev/null +++ b/src/util/enum.zig @@ -0,0 +1,56 @@ +const std = @import("std"); + +pub fn enumFieldsSlice(comptime T: type) []const T { + var fields: []const T = &[_]T{}; + inline for (@typeInfo(T).Enum.fields) |enumField| { + fields = fields ++ &[_]T{ + @field(T, enumField.name), + }; + } + return fields; +} + +/// Creates an slice of slices with with fields in the given enum. +/// Runs `F` for each field in `T` to modify the names in the resulting slice. +pub fn enumFieldsStringSlice( + comptime T: type, + comptime F: ?fn (comptime []const u8) []const u8, +) []const []const u8 { + @setEvalBranchQuota(10000); + var names: []const []const u8 = &[_][]const u8{}; + for (std.meta.fields(T)) |field| { + const name = blk: { + if (F) |f| break :blk f(field.name); + break :blk field.name; + }; + names = names ++ &[_][]const u8{name}; + } + return names; +} + +const TestEnum = enum { + A_A, + B_B, +}; + +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 "enumFieldsSlice" { + const fields = comptime enumFieldsSlice(TestEnum); + try std.testing.expect(fields.len == 2); + try std.testing.expect(fields[@enumToInt(TestEnum.A_A)] == TestEnum.A_A); + try std.testing.expect(fields[@enumToInt(TestEnum.B_B)] == TestEnum.B_B); +} + +test "enumFieldsStringSlice" { + const fields = comptime enumFieldsStringSlice(TestEnum, replaceUnderscores); + const a = TestEnum.A_A; + const b = TestEnum.B_B; + try std.testing.expect(fields.len == 2); + try std.testing.expect(std.mem.eql(u8, fields[@enumToInt(a)], "A-A")); + try std.testing.expect(std.mem.eql(u8, fields[@enumToInt(b)], "B-B")); +} diff --git a/src/util/struct.zig b/src/util/struct.zig new file mode 100644 index 0000000..db41b09 --- /dev/null +++ b/src/util/struct.zig @@ -0,0 +1,85 @@ +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")); + } +} |