summaryrefslogtreecommitdiff
path: root/src/util/struct.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/util/struct.zig')
-rw-r--r--src/util/struct.zig85
1 files changed, 85 insertions, 0 deletions
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"));
+ }
+}