From ac19ccf5955488a43b29ea13675c33426aada430 Mon Sep 17 00:00:00 2001 From: Tadeo Kondrak Date: Wed, 26 Aug 2020 12:20:27 -0600 Subject: [PATCH] Update standard library for removal of TypeInfo.UnionField.enum_field --- lib/std/fmt.zig | 8 +++++++- lib/std/hash/auto_hash.zig | 11 ++++++++--- lib/std/io/serialization.zig | 18 ++++++++++++++++-- lib/std/json.zig | 16 ++++++++++++++-- lib/std/meta.zig | 24 +++++++++++++++++++----- 5 files changed, 64 insertions(+), 13 deletions(-) diff --git a/lib/std/fmt.zig b/lib/std/fmt.zig index a652bd8c21..3aa6278d5d 100644 --- a/lib/std/fmt.zig +++ b/lib/std/fmt.zig @@ -395,11 +395,17 @@ pub fn formatType( } const info = @typeInfo(T).Union; if (info.tag_type) |UnionTagType| { + const tag_info = @typeInfo(UnionTagType).Enum; try writer.writeAll("{ ."); try writer.writeAll(@tagName(@as(UnionTagType, value))); try writer.writeAll(" = "); inline for (info.fields) |u_field| { - if (@enumToInt(@as(UnionTagType, value)) == u_field.enum_field.?.value) { + comptime var tag_value: @TagType(UnionTagType) = undefined; + inline for (tag_info.fields) |e_field| { + if (comptime mem.eql(u8, u_field.name, e_field.name)) + tag_value = e_field.value; + } + if (@enumToInt(@as(UnionTagType, value)) == tag_value) { try formatType(@field(value, u_field.name), fmt, options, writer, max_depth - 1); } } diff --git a/lib/std/hash/auto_hash.zig b/lib/std/hash/auto_hash.zig index 5877c77b5d..c3beabe007 100644 --- a/lib/std/hash/auto_hash.zig +++ b/lib/std/hash/auto_hash.zig @@ -136,12 +136,17 @@ pub fn hash(hasher: anytype, key: anytype, comptime strat: HashStrategy) void { .Union => |info| { if (info.tag_type) |tag_type| { + const tag_info = @typeInfo(tag_type).Enum; const tag = meta.activeTag(key); const s = hash(hasher, tag, strat); inline for (info.fields) |field| { - const enum_field = field.enum_field.?; - if (enum_field.value == @enumToInt(tag)) { - hash(hasher, @field(key, enum_field.name), strat); + comptime var tag_value: @TagType(tag_type) = undefined; + inline for (tag_info.fields) |enum_field| { + if (comptime mem.eql(u8, field.name, enum_field.name)) + tag_value = enum_field.value; + } + if (@enumToInt(tag) == tag_value) { + hash(hasher, @field(key, field.name), strat); // TODO use a labelled break when it does not crash the compiler. cf #2908 // break :blk; return; diff --git a/lib/std/io/serialization.zig b/lib/std/io/serialization.zig index 925c929cee..fa5172e57f 100644 --- a/lib/std/io/serialization.zig +++ b/lib/std/io/serialization.zig @@ -149,6 +149,7 @@ pub fn Deserializer(comptime endian: builtin.Endian, comptime packing: Packing, .Union => { const info = @typeInfo(C).Union; if (info.tag_type) |TagType| { + const tag_info = @typeInfo(TagType).Enum; //we avoid duplicate iteration over the enum tags // by getting the int directly and casting it without // safety. If it is bad, it will be caught anyway. @@ -156,7 +157,13 @@ pub fn Deserializer(comptime endian: builtin.Endian, comptime packing: Packing, const tag = try self.deserializeInt(TagInt); inline for (info.fields) |field_info| { - if (field_info.enum_field.?.value == tag) { + comptime var tag_value: TagInt = undefined; + inline for (tag_info.fields) |enum_field_info| { + if (comptime std.mem.eql(u8, field_info.name, enum_field_info.name)) { + tag_value = enum_field_info.value; + } + } + if (tag_value == tag) { const name = field_info.name; const FieldType = field_info.field_type; ptr.* = @unionInit(C, name, undefined); @@ -314,13 +321,20 @@ pub fn Serializer(comptime endian: builtin.Endian, comptime packing: Packing, co .Union => { const info = @typeInfo(T).Union; if (info.tag_type) |TagType| { + const tag_info = @typeInfo(TagType).Enum; const active_tag = meta.activeTag(value); try self.serialize(active_tag); //This inline loop is necessary because active_tag is a runtime // value, but @field requires a comptime value. Our alternative // is to check each field for a match inline for (info.fields) |field_info| { - if (field_info.enum_field.?.value == @enumToInt(active_tag)) { + comptime var tag_value: @TagType(TagType) = undefined; + inline for (tag_info.fields) |enum_field_info| { + if (comptime std.mem.eql(u8, field_info.name, enum_field_info.name)) { + tag_value = enum_field_info.value; + } + } + if (tag_value == @enumToInt(active_tag)) { const name = field_info.name; const FieldType = field_info.field_type; try self.serialize(@field(value, name)); diff --git a/lib/std/json.zig b/lib/std/json.zig index 2f8a70d0ef..31f8a91127 100644 --- a/lib/std/json.zig +++ b/lib/std/json.zig @@ -1612,8 +1612,14 @@ pub fn parseFree(comptime T: type, value: T, options: ParseOptions) void { }, .Union => |unionInfo| { if (unionInfo.tag_type) |UnionTagType| { + const tag_info = @typeInfo(UnionTagType).Enum; inline for (unionInfo.fields) |u_field| { - if (@enumToInt(@as(UnionTagType, value)) == u_field.enum_field.?.value) { + comptime var tag_value: @TagType(UnionTagType) = undefined; + inline for (tag_info.fields) |e_field| { + if (comptime mem.eql(u8, u_field.name, e_field.name)) + tag_value = e_field.value; + } + if (@enumToInt(@as(UnionTagType, value)) == tag_value) { parseFree(u_field.field_type, @field(value, u_field.name), options); break; } @@ -2457,8 +2463,14 @@ pub fn stringify( const info = @typeInfo(T).Union; if (info.tag_type) |UnionTagType| { + const tag_info = @typeInfo(UnionTagType).Enum; inline for (info.fields) |u_field| { - if (@enumToInt(@as(UnionTagType, value)) == u_field.enum_field.?.value) { + comptime var tag_value: @TagType(UnionTagType) = undefined; + inline for (tag_info.fields) |e_field| { + if (comptime mem.eql(u8, u_field.name, e_field.name)) + tag_value = e_field.value; + } + if (@enumToInt(@as(UnionTagType, value)) == tag_value) { return try stringify(@field(value, u_field.name), options, out_stream); } } diff --git a/lib/std/meta.zig b/lib/std/meta.zig index 73e0661498..8cb1ba155d 100644 --- a/lib/std/meta.zig +++ b/lib/std/meta.zig @@ -465,10 +465,19 @@ pub fn TagPayloadType(comptime U: type, tag: @TagType(U)) type { testing.expect(trait.is(.Union)(U)); const info = @typeInfo(U).Union; + const tag_info = @typeInfo(@TagType(U)).Enum; + + comptime var name: []const u8 = undefined; + inline for (tag_info.fields) |enum_field_info| { + if (@enumToInt(tag) == enum_field_info.value) + name = enum_field_info.name; + } inline for (info.fields) |field_info| { - if (field_info.enum_field.?.value == @enumToInt(tag)) return field_info.field_type; + if (comptime mem.eql(u8, field_info.name, name)) + return field_info.field_type; } + unreachable; } @@ -504,15 +513,20 @@ pub fn eql(a: anytype, b: @TypeOf(a)) bool { } }, .Union => |info| { - if (info.tag_type) |_| { + if (info.tag_type) |Tag| { const tag_a = activeTag(a); const tag_b = activeTag(b); if (tag_a != tag_b) return false; + const tag_info = @typeInfo(Tag).Enum; inline for (info.fields) |field_info| { - const enum_field = field_info.enum_field.?; - if (enum_field.value == @enumToInt(tag_a)) { - return eql(@field(a, enum_field.name), @field(b, enum_field.name)); + comptime var tag_value: @TagType(Tag) = undefined; + inline for (tag_info.fields) |enum_field_info| { + if (comptime mem.eql(u8, field_info.name, enum_field_info.name)) + tag_value = enum_field_info.value; + } + if (tag_value == @enumToInt(tag_a)) { + return eql(@field(a, field_info.name), @field(b, field_info.name)); } } return false;