summaryrefslogtreecommitdiff
path: root/src/util
diff options
context:
space:
mode:
Diffstat (limited to 'src/util')
-rw-r--r--src/util/enum.zig56
-rw-r--r--src/util/struct.zig85
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"));
+ }
+}