diff --git a/lib/std/meta.zig b/lib/std/meta.zig index 3396a4122c..2644752db7 100644 --- a/lib/std/meta.zig +++ b/lib/std/meta.zig @@ -57,6 +57,54 @@ test "std.meta.tagName" { try testing.expect(mem.eql(u8, tagName(u2b), "D")); } +/// Given an enum or tagged union, returns true if the comptime-supplied +/// string matches the name of the tag value. This match process should +/// be, at runtime, O(1) in the number of tags available to the enum or +/// union, and it should also be O(1) in the length of the comptime tag +/// names. +pub fn isTag(tagged_value: anytype, comptime tag_name: []const u8) bool { + const T = @TypeOf(tagged_value); + const type_info = @typeInfo(T); + const type_name = @typeName(T); + + // select the Enum type out of the type (in the case of the tagged union, extract it) + const E = if (.Enum == type_info) T else if (.Union == type_info) (if (type_info.Union.tag_type) |TT| TT else { + @compileError("attempted to use isTag on the untagged union " ++ type_name); + }) else { + @compileError("attempted to use isTag on a value of type (" ++ type_name ++ ") that isn't an enum or a union."); + }; + + return tagged_value == @field(E, tag_name); +} + +test "std.meta.isTag for Enums" { + const EnumType = enum { a, b }; + var a_type: EnumType = .a; + var b_type: EnumType = .b; + + try testing.expect(isTag(a_type, "a")); + try testing.expect(!isTag(a_type, "b")); + try testing.expect(isTag(b_type, "b")); + try testing.expect(!isTag(b_type, "a")); +} + +test "std.meta.isTag for Tagged Unions" { + const TaggedUnionEnum = enum { int, flt }; + + const TaggedUnionType = union(TaggedUnionEnum) { + int: i64, + flt: f64, + }; + + var int = TaggedUnionType{ .int = 1234 }; + var flt = TaggedUnionType{ .flt = 12.34 }; + + try testing.expect(isTag(int, "int")); + try testing.expect(!isTag(int, "flt")); + try testing.expect(isTag(flt, "flt")); + try testing.expect(!isTag(flt, "int")); +} + pub fn stringToEnum(comptime T: type, str: []const u8) ?T { // Using ComptimeStringMap here is more performant, but it will start to take too // long to compile if the enum is large enough, due to the current limits of comptime