authorgravatar for 14938807+xackus@users.noreply.github.comxackus <14938807+xackus@users.noreply.github.com> 2020-02-13 23:20:40+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-02-14 09:35:38-05:00
log7396b144ba72d28d10ee1e089fc8e4f87239a840
tree7b15efc5ba88641c730cffbef8b6540b6d986e30
parentfb6b94f80fed42b4c690b43a875bf0a58977493e

modernize std.meta


2 files changed, 95 insertions(+), 126 deletions(-)

lib/std/meta.zig+52-62
......@@ -7,13 +7,12 @@ const testing = std.testing;
77
88pub const trait = @import("meta/trait.zig");
99
10const TypeId = builtin.TypeId;
1110const TypeInfo = builtin.TypeInfo;
1211
1312pub fn tagName(v: var) []const u8 {
1413 const T = @TypeOf(v);
1514 switch (@typeInfo(T)) {
16 TypeId.ErrorSet => return @errorName(v),
15 .ErrorSet => return @errorName(v),
1716 else => return @tagName(v),
1817 }
1918}
......@@ -55,7 +54,7 @@ test "std.meta.tagName" {
5554
5655pub fn stringToEnum(comptime T: type, str: []const u8) ?T {
5756 inline for (@typeInfo(T).Enum.fields) |enumField| {
58 if (std.mem.eql(u8, str, enumField.name)) {
57 if (mem.eql(u8, str, enumField.name)) {
5958 return @field(T, enumField.name);
6059 }
6160 }
......@@ -74,9 +73,9 @@ test "std.meta.stringToEnum" {
7473
7574pub fn bitCount(comptime T: type) comptime_int {
7675 return switch (@typeInfo(T)) {
77 TypeId.Bool => 1,
78 TypeId.Int => |info| info.bits,
79 TypeId.Float => |info| info.bits,
76 .Bool => 1,
77 .Int => |info| info.bits,
78 .Float => |info| info.bits,
8079 else => @compileError("Expected bool, int or float type, found '" ++ @typeName(T) ++ "'"),
8180 };
8281}
......@@ -88,7 +87,7 @@ test "std.meta.bitCount" {
8887
8988pub fn alignment(comptime T: type) comptime_int {
9089 //@alignOf works on non-pointer types
91 const P = if (comptime trait.is(TypeId.Pointer)(T)) T else *T;
90 const P = if (comptime trait.is(.Pointer)(T)) T else *T;
9291 return @typeInfo(P).Pointer.alignment;
9392}
9493
......@@ -102,9 +101,9 @@ test "std.meta.alignment" {
102101
103102pub fn Child(comptime T: type) type {
104103 return switch (@typeInfo(T)) {
105 TypeId.Array => |info| info.child,
106 TypeId.Pointer => |info| info.child,
107 TypeId.Optional => |info| info.child,
104 .Array => |info| info.child,
105 .Pointer => |info| info.child,
106 .Optional => |info| info.child,
108107 else => @compileError("Expected pointer, optional, or array type, " ++ "found '" ++ @typeName(T) ++ "'"),
109108 };
110109}
......@@ -118,9 +117,9 @@ test "std.meta.Child" {
118117
119118pub fn containerLayout(comptime T: type) TypeInfo.ContainerLayout {
120119 return switch (@typeInfo(T)) {
121 TypeId.Struct => |info| info.layout,
122 TypeId.Enum => |info| info.layout,
123 TypeId.Union => |info| info.layout,
120 .Struct => |info| info.layout,
121 .Enum => |info| info.layout,
122 .Union => |info| info.layout,
124123 else => @compileError("Expected struct, enum or union type, found '" ++ @typeName(T) ++ "'"),
125124 };
126125}
......@@ -148,22 +147,22 @@ test "std.meta.containerLayout" {
148147 a: u8,
149148 };
150149
151 testing.expect(containerLayout(E1) == TypeInfo.ContainerLayout.Auto);
152 testing.expect(containerLayout(E2) == TypeInfo.ContainerLayout.Packed);
153 testing.expect(containerLayout(E3) == TypeInfo.ContainerLayout.Extern);
154 testing.expect(containerLayout(S1) == TypeInfo.ContainerLayout.Auto);
155 testing.expect(containerLayout(S2) == TypeInfo.ContainerLayout.Packed);
156 testing.expect(containerLayout(S3) == TypeInfo.ContainerLayout.Extern);
157 testing.expect(containerLayout(U1) == TypeInfo.ContainerLayout.Auto);
158 testing.expect(containerLayout(U2) == TypeInfo.ContainerLayout.Packed);
159 testing.expect(containerLayout(U3) == TypeInfo.ContainerLayout.Extern);
150 testing.expect(containerLayout(E1) == .Auto);
151 testing.expect(containerLayout(E2) == .Packed);
152 testing.expect(containerLayout(E3) == .Extern);
153 testing.expect(containerLayout(S1) == .Auto);
154 testing.expect(containerLayout(S2) == .Packed);
155 testing.expect(containerLayout(S3) == .Extern);
156 testing.expect(containerLayout(U1) == .Auto);
157 testing.expect(containerLayout(U2) == .Packed);
158 testing.expect(containerLayout(U3) == .Extern);
160159}
161160
162161pub fn declarations(comptime T: type) []TypeInfo.Declaration {
163162 return switch (@typeInfo(T)) {
164 TypeId.Struct => |info| info.decls,
165 TypeId.Enum => |info| info.decls,
166 TypeId.Union => |info| info.decls,
163 .Struct => |info| info.decls,
164 .Enum => |info| info.decls,
165 .Union => |info| info.decls,
167166 else => @compileError("Expected struct, enum or union type, found '" ++ @typeName(T) ++ "'"),
168167 };
169168}
......@@ -232,17 +231,17 @@ test "std.meta.declarationInfo" {
232231}
233232
234233pub fn fields(comptime T: type) switch (@typeInfo(T)) {
235 TypeId.Struct => []TypeInfo.StructField,
236 TypeId.Union => []TypeInfo.UnionField,
237 TypeId.ErrorSet => []TypeInfo.Error,
238 TypeId.Enum => []TypeInfo.EnumField,
234 .Struct => []TypeInfo.StructField,
235 .Union => []TypeInfo.UnionField,
236 .ErrorSet => []TypeInfo.Error,
237 .Enum => []TypeInfo.EnumField,
239238 else => @compileError("Expected struct, union, error set or enum type, found '" ++ @typeName(T) ++ "'"),
240239} {
241240 return switch (@typeInfo(T)) {
242 TypeId.Struct => |info| info.fields,
243 TypeId.Union => |info| info.fields,
244 TypeId.Enum => |info| info.fields,
245 TypeId.ErrorSet => |errors| errors.?, // must be non global error set
241 .Struct => |info| info.fields,
242 .Union => |info| info.fields,
243 .Enum => |info| info.fields,
244 .ErrorSet => |errors| errors.?, // must be non global error set
246245 else => @compileError("Expected struct, union, error set or enum type, found '" ++ @typeName(T) ++ "'"),
247246 };
248247}
......@@ -277,10 +276,10 @@ test "std.meta.fields" {
277276}
278277
279278pub fn fieldInfo(comptime T: type, comptime field_name: []const u8) switch (@typeInfo(T)) {
280 TypeId.Struct => TypeInfo.StructField,
281 TypeId.Union => TypeInfo.UnionField,
282 TypeId.ErrorSet => TypeInfo.Error,
283 TypeId.Enum => TypeInfo.EnumField,
279 .Struct => TypeInfo.StructField,
280 .Union => TypeInfo.UnionField,
281 .ErrorSet => TypeInfo.Error,
282 .Enum => TypeInfo.EnumField,
284283 else => @compileError("Expected struct, union, error set or enum type, found '" ++ @typeName(T) ++ "'"),
285284} {
286285 inline for (comptime fields(T)) |field| {
......@@ -318,8 +317,8 @@ test "std.meta.fieldInfo" {
318317
319318pub fn TagType(comptime T: type) type {
320319 return switch (@typeInfo(T)) {
321 TypeId.Enum => |info| info.tag_type,
322 TypeId.Union => |info| if (info.tag_type) |Tag| Tag else null,
320 .Enum => |info| info.tag_type,
321 .Union => |info| if (info.tag_type) |Tag| Tag else null,
323322 else => @compileError("expected enum or union type, found '" ++ @typeName(T) ++ "'"),
324323 };
325324}
......@@ -365,7 +364,7 @@ test "std.meta.activeTag" {
365364///Given a tagged union type, and an enum, return the type of the union
366365/// field corresponding to the enum tag.
367366pub fn TagPayloadType(comptime U: type, tag: @TagType(U)) type {
368 testing.expect(trait.is(builtin.TypeId.Union)(U));
367 testing.expect(trait.is(.Union)(U));
369368
370369 const info = @typeInfo(U).Union;
371370
......@@ -387,30 +386,26 @@ test "std.meta.TagPayloadType" {
387386 testing.expect(MovedEvent == @TypeOf(e.Moved));
388387}
389388
390///Compares two of any type for equality. Containers are compared on a field-by-field basis,
389/// Compares two of any type for equality. Containers are compared on a field-by-field basis,
391390/// where possible. Pointers are not followed.
392391pub fn eql(a: var, b: @TypeOf(a)) bool {
393392 const T = @TypeOf(a);
394393
395 switch (@typeId(T)) {
396 builtin.TypeId.Struct => {
397 const info = @typeInfo(T).Struct;
398
394 switch (@typeInfo(T)) {
395 .Struct => |info| {
399396 inline for (info.fields) |field_info| {
400397 if (!eql(@field(a, field_info.name), @field(b, field_info.name))) return false;
401398 }
402399 return true;
403400 },
404 builtin.TypeId.ErrorUnion => {
401 .ErrorUnion => {
405402 if (a) |a_p| {
406403 if (b) |b_p| return eql(a_p, b_p) else |_| return false;
407404 } else |a_e| {
408405 if (b) |_| return false else |b_e| return a_e == b_e;
409406 }
410407 },
411 builtin.TypeId.Union => {
412 const info = @typeInfo(T).Union;
413
408 .Union => |info| {
414409 if (info.tag_type) |_| {
415410 const tag_a = activeTag(a);
416411 const tag_b = activeTag(b);
......@@ -427,31 +422,26 @@ pub fn eql(a: var, b: @TypeOf(a)) bool {
427422
428423 @compileError("cannot compare untagged union type " ++ @typeName(T));
429424 },
430 builtin.TypeId.Array => {
425 .Array => {
431426 if (a.len != b.len) return false;
432427 for (a) |e, i|
433428 if (!eql(e, b[i])) return false;
434429 return true;
435430 },
436 builtin.TypeId.Vector => {
437 const info = @typeInfo(T).Vector;
431 .Vector => |info| {
438432 var i: usize = 0;
439433 while (i < info.len) : (i += 1) {
440434 if (!eql(a[i], b[i])) return false;
441435 }
442436 return true;
443437 },
444 builtin.TypeId.Pointer => {
445 const info = @typeInfo(T).Pointer;
446 switch (info.size) {
447 builtin.TypeInfo.Pointer.Size.One,
448 builtin.TypeInfo.Pointer.Size.Many,
449 builtin.TypeInfo.Pointer.Size.C,
450 => return a == b,
451 builtin.TypeInfo.Pointer.Size.Slice => return a.ptr == b.ptr and a.len == b.len,
452 }
438 .Pointer => |info| {
439 return switch (info.size) {
440 .One, .Many, .C, => a == b,
441 .Slice => a.ptr == b.ptr and a.len == b.len,
442 };
453443 },
454 builtin.TypeId.Optional => {
444 .Optional => {
455445 if (a == null and b == null) return true;
456446 if (a == null or b == null) return false;
457447 return eql(a.?, b.?);
lib/std/meta/trait.zig+43-64
......@@ -7,17 +7,11 @@ const warn = debug.warn;
77
88const meta = @import("../meta.zig");
99
10//This is necessary if we want to return generic functions directly because of how the
11// the type erasure works. see: #1375
12fn traitFnWorkaround(comptime T: type) bool {
13 return false;
14}
15
16pub const TraitFn = @TypeOf(traitFnWorkaround);
10pub const TraitFn = fn (type) bool;
1711
1812//////Trait generators
1913
20//Need TraitList because compiler can't do varargs at comptime yet
14// TODO convert to tuples when #4335 is done
2115pub const TraitList = []const TraitFn;
2216pub fn multiTrait(comptime traits: TraitList) TraitFn {
2317 const Closure = struct {
......@@ -60,8 +54,7 @@ pub fn hasFn(comptime name: []const u8) TraitFn {
6054 if (!comptime isContainer(T)) return false;
6155 if (!comptime @hasDecl(T, name)) return false;
6256 const DeclType = @TypeOf(@field(T, name));
63 const decl_type_id = @typeId(DeclType);
64 return decl_type_id == builtin.TypeId.Fn;
57 return @typeId(DeclType) == .Fn;
6558 }
6659 };
6760 return Closure.trait;
......@@ -80,11 +73,10 @@ test "std.meta.trait.hasFn" {
8073pub fn hasField(comptime name: []const u8) TraitFn {
8174 const Closure = struct {
8275 pub fn trait(comptime T: type) bool {
83 const info = @typeInfo(T);
84 const fields = switch (info) {
85 builtin.TypeId.Struct => |s| s.fields,
86 builtin.TypeId.Union => |u| u.fields,
87 builtin.TypeId.Enum => |e| e.fields,
76 const fields = switch (@typeInfo(T)) {
77 .Struct => |s| s.fields,
78 .Union => |u| u.fields,
79 .Enum => |e| e.fields,
8880 else => return false,
8981 };
9082
......@@ -120,11 +112,11 @@ pub fn is(comptime id: builtin.TypeId) TraitFn {
120112}
121113
122114test "std.meta.trait.is" {
123 testing.expect(is(builtin.TypeId.Int)(u8));
124 testing.expect(!is(builtin.TypeId.Int)(f32));
125 testing.expect(is(builtin.TypeId.Pointer)(*u8));
126 testing.expect(is(builtin.TypeId.Void)(void));
127 testing.expect(!is(builtin.TypeId.Optional)(anyerror));
115 testing.expect(is(.Int)(u8));
116 testing.expect(!is(.Int)(f32));
117 testing.expect(is(.Pointer)(*u8));
118 testing.expect(is(.Void)(void));
119 testing.expect(!is(.Optional)(anyerror));
128120}
129121
130122pub fn isPtrTo(comptime id: builtin.TypeId) TraitFn {
......@@ -138,9 +130,9 @@ pub fn isPtrTo(comptime id: builtin.TypeId) TraitFn {
138130}
139131
140132test "std.meta.trait.isPtrTo" {
141 testing.expect(!isPtrTo(builtin.TypeId.Struct)(struct {}));
142 testing.expect(isPtrTo(builtin.TypeId.Struct)(*struct {}));
143 testing.expect(!isPtrTo(builtin.TypeId.Struct)(**struct {}));
133 testing.expect(!isPtrTo(.Struct)(struct {}));
134 testing.expect(isPtrTo(.Struct)(*struct {}));
135 testing.expect(!isPtrTo(.Struct)(**struct {}));
144136}
145137
146138///////////Strait trait Fns
......@@ -149,12 +141,10 @@ test "std.meta.trait.isPtrTo" {
149141// Somewhat limited since we can't apply this logic to normal variables, fields, or
150142// Fns yet. Should be isExternType?
151143pub fn isExtern(comptime T: type) bool {
152 const Extern = builtin.TypeInfo.ContainerLayout.Extern;
153 const info = @typeInfo(T);
154 return switch (info) {
155 builtin.TypeId.Struct => |s| s.layout == Extern,
156 builtin.TypeId.Union => |u| u.layout == Extern,
157 builtin.TypeId.Enum => |e| e.layout == Extern,
144 return switch (@typeInfo(T)) {
145 .Struct => |s| s.layout == .Extern,
146 .Union => |u| u.layout == .Extern,
147 .Enum => |e| e.layout == .Extern,
158148 else => false,
159149 };
160150}
......@@ -169,12 +159,10 @@ test "std.meta.trait.isExtern" {
169159}
170160
171161pub fn isPacked(comptime T: type) bool {
172 const Packed = builtin.TypeInfo.ContainerLayout.Packed;
173 const info = @typeInfo(T);
174 return switch (info) {
175 builtin.TypeId.Struct => |s| s.layout == Packed,
176 builtin.TypeId.Union => |u| u.layout == Packed,
177 builtin.TypeId.Enum => |e| e.layout == Packed,
162 return switch (@typeInfo(T)) {
163 .Struct => |s| s.layout == .Packed,
164 .Union => |u| u.layout == .Packed,
165 .Enum => |e| e.layout == .Packed,
178166 else => false,
179167 };
180168}
......@@ -189,8 +177,8 @@ test "std.meta.trait.isPacked" {
189177}
190178
191179pub fn isUnsignedInt(comptime T: type) bool {
192 return switch (@typeId(T)) {
193 builtin.TypeId.Int => !@typeInfo(T).Int.is_signed,
180 return switch (@typeInfo(T)) {
181 .Int => |i| !i.is_signed,
194182 else => false,
195183 };
196184}
......@@ -203,9 +191,9 @@ test "isUnsignedInt" {
203191}
204192
205193pub fn isSignedInt(comptime T: type) bool {
206 return switch (@typeId(T)) {
207 builtin.TypeId.ComptimeInt => true,
208 builtin.TypeId.Int => @typeInfo(T).Int.is_signed,
194 return switch (@typeInfo(T)) {
195 .ComptimeInt => true,
196 .Int => |i| i.is_signed,
209197 else => false,
210198 };
211199}
......@@ -218,9 +206,8 @@ test "isSignedInt" {
218206}
219207
220208pub fn isSingleItemPtr(comptime T: type) bool {
221 if (comptime is(builtin.TypeId.Pointer)(T)) {
222 const info = @typeInfo(T);
223 return info.Pointer.size == builtin.TypeInfo.Pointer.Size.One;
209 if (comptime is(.Pointer)(T)) {
210 return @typeInfo(T).Pointer.size == .One;
224211 }
225212 return false;
226213}
......@@ -233,9 +220,8 @@ test "std.meta.trait.isSingleItemPtr" {
233220}
234221
235222pub fn isManyItemPtr(comptime T: type) bool {
236 if (comptime is(builtin.TypeId.Pointer)(T)) {
237 const info = @typeInfo(T);
238 return info.Pointer.size == builtin.TypeInfo.Pointer.Size.Many;
223 if (comptime is(.Pointer)(T)) {
224 return @typeInfo(T).Pointer.size == .Many;
239225 }
240226 return false;
241227}
......@@ -249,9 +235,8 @@ test "std.meta.trait.isManyItemPtr" {
249235}
250236
251237pub fn isSlice(comptime T: type) bool {
252 if (comptime is(builtin.TypeId.Pointer)(T)) {
253 const info = @typeInfo(T);
254 return info.Pointer.size == builtin.TypeInfo.Pointer.Size.Slice;
238 if (comptime is(.Pointer)(T)) {
239 return @typeInfo(T).Pointer.size == .Slice;
255240 }
256241 return false;
257242}
......@@ -264,15 +249,13 @@ test "std.meta.trait.isSlice" {
264249}
265250
266251pub fn isIndexable(comptime T: type) bool {
267 if (comptime is(builtin.TypeId.Pointer)(T)) {
268 const info = @typeInfo(T);
269 if (info.Pointer.size == builtin.TypeInfo.Pointer.Size.One) {
270 if (comptime is(builtin.TypeId.Array)(meta.Child(T))) return true;
271 return false;
252 if (comptime is(.Pointer)(T)) {
253 if (@typeInfo(T).Pointer.size == .One) {
254 return (comptime is(.Array)(meta.Child(T)));
272255 }
273256 return true;
274257 }
275 return comptime is(builtin.TypeId.Array)(T);
258 return comptime is(.Array)(T);
276259}
277260
278261test "std.meta.trait.isIndexable" {
......@@ -287,7 +270,7 @@ test "std.meta.trait.isIndexable" {
287270
288271pub fn isNumber(comptime T: type) bool {
289272 return switch (@typeId(T)) {
290 builtin.TypeId.Int, builtin.TypeId.Float, builtin.TypeId.ComptimeInt, builtin.TypeId.ComptimeFloat => true,
273 .Int, .Float, .ComptimeInt, .ComptimeFloat => true,
291274 else => false,
292275 };
293276}
......@@ -307,9 +290,8 @@ test "std.meta.trait.isNumber" {
307290}
308291
309292pub fn isConstPtr(comptime T: type) bool {
310 if (!comptime is(builtin.TypeId.Pointer)(T)) return false;
311 const info = @typeInfo(T);
312 return info.Pointer.is_const;
293 if (!comptime is(.Pointer)(T)) return false;
294 return @typeInfo(T).Pointer.is_const;
313295}
314296
315297test "std.meta.trait.isConstPtr" {
......@@ -322,11 +304,8 @@ test "std.meta.trait.isConstPtr" {
322304}
323305
324306pub fn isContainer(comptime T: type) bool {
325 const info = @typeInfo(T);
326 return switch (info) {
327 builtin.TypeId.Struct => true,
328 builtin.TypeId.Union => true,
329 builtin.TypeId.Enum => true,
307 return switch (@typeId(T)) {
308 .Struct, .Union, .Enum => true,
330309 else => false,
331310 };
332311}