Skip to content

Commit

Permalink
adds isTag function to std.meta (#11895)
Browse files Browse the repository at this point in the history
  • Loading branch information
ityonemo authored Oct 15, 2022
1 parent c0d7f64 commit 99c3578
Showing 1 changed file with 48 additions and 0 deletions.
48 changes: 48 additions & 0 deletions lib/std/meta.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 99c3578

Please sign in to comment.