master
   1const builtin = @import("builtin");
   2const std = @import("std.zig");
   3const debug = std.debug;
   4const mem = std.mem;
   5const math = std.math;
   6const testing = std.testing;
   7const root = @import("root");
   8
   9pub const TrailerFlags = @import("meta/trailer_flags.zig").TrailerFlags;
  10
  11const Type = std.builtin.Type;
  12
  13test {
  14    _ = TrailerFlags;
  15}
  16
  17/// Returns the variant of an enum type, `T`, which is named `str`, or `null` if no such variant exists.
  18pub fn stringToEnum(comptime T: type, str: []const u8) ?T {
  19    // Using StaticStringMap here is more performant, but it will start to take too
  20    // long to compile if the enum is large enough, due to the current limits of comptime
  21    // performance when doing things like constructing lookup maps at comptime.
  22    // TODO The '100' here is arbitrary and should be increased when possible:
  23    // - https://github.com/ziglang/zig/issues/4055
  24    // - https://github.com/ziglang/zig/issues/3863
  25    if (@typeInfo(T).@"enum".fields.len <= 100) {
  26        const kvs = comptime build_kvs: {
  27            const EnumKV = struct { []const u8, T };
  28            var kvs_array: [@typeInfo(T).@"enum".fields.len]EnumKV = undefined;
  29            for (@typeInfo(T).@"enum".fields, 0..) |enumField, i| {
  30                kvs_array[i] = .{ enumField.name, @field(T, enumField.name) };
  31            }
  32            break :build_kvs kvs_array[0..];
  33        };
  34        const map = std.StaticStringMap(T).initComptime(kvs);
  35        return map.get(str);
  36    } else {
  37        inline for (@typeInfo(T).@"enum".fields) |enumField| {
  38            if (mem.eql(u8, str, enumField.name)) {
  39                return @field(T, enumField.name);
  40            }
  41        }
  42        return null;
  43    }
  44}
  45
  46test stringToEnum {
  47    const E1 = enum {
  48        A,
  49        B,
  50    };
  51    try testing.expect(E1.A == stringToEnum(E1, "A").?);
  52    try testing.expect(E1.B == stringToEnum(E1, "B").?);
  53    try testing.expect(null == stringToEnum(E1, "C"));
  54}
  55
  56/// Returns the alignment of type T.
  57/// Note that if T is a pointer type the result is different than the one
  58/// returned by @alignOf(T).
  59/// If T is a pointer type the alignment of the type it points to is returned.
  60pub fn alignment(comptime T: type) comptime_int {
  61    return switch (@typeInfo(T)) {
  62        .optional => |info| switch (@typeInfo(info.child)) {
  63            .pointer, .@"fn" => alignment(info.child),
  64            else => @alignOf(T),
  65        },
  66        .pointer => |info| info.alignment,
  67        else => @alignOf(T),
  68    };
  69}
  70
  71test alignment {
  72    try testing.expect(alignment(u8) == 1);
  73    try testing.expect(alignment(*align(1) u8) == 1);
  74    try testing.expect(alignment(*align(2) u8) == 2);
  75    try testing.expect(alignment([]align(1) u8) == 1);
  76    try testing.expect(alignment([]align(2) u8) == 2);
  77    try testing.expect(alignment(fn () void) > 0);
  78    try testing.expect(alignment(*const fn () void) > 0);
  79    try testing.expect(alignment(*align(128) const fn () void) == 128);
  80}
  81
  82/// Given a parameterized type (array, vector, pointer, optional), returns the "child type".
  83pub fn Child(comptime T: type) type {
  84    return switch (@typeInfo(T)) {
  85        .array => |info| info.child,
  86        .vector => |info| info.child,
  87        .pointer => |info| info.child,
  88        .optional => |info| info.child,
  89        else => @compileError("Expected pointer, optional, array or vector type, found '" ++ @typeName(T) ++ "'"),
  90    };
  91}
  92
  93test Child {
  94    try testing.expect(Child([1]u8) == u8);
  95    try testing.expect(Child(*u8) == u8);
  96    try testing.expect(Child([]u8) == u8);
  97    try testing.expect(Child(?u8) == u8);
  98    try testing.expect(Child(@Vector(2, u8)) == u8);
  99}
 100
 101/// Given a "memory span" type (array, slice, vector, or pointer to such), returns the "element type".
 102pub fn Elem(comptime T: type) type {
 103    switch (@typeInfo(T)) {
 104        .array => |info| return info.child,
 105        .vector => |info| return info.child,
 106        .pointer => |info| switch (info.size) {
 107            .one => switch (@typeInfo(info.child)) {
 108                .array => |array_info| return array_info.child,
 109                .vector => |vector_info| return vector_info.child,
 110                else => {},
 111            },
 112            .many, .c, .slice => return info.child,
 113        },
 114        .optional => |info| return Elem(info.child),
 115        else => {},
 116    }
 117    @compileError("Expected pointer, slice, array or vector type, found '" ++ @typeName(T) ++ "'");
 118}
 119
 120test Elem {
 121    try testing.expect(Elem([1]u8) == u8);
 122    try testing.expect(Elem([*]u8) == u8);
 123    try testing.expect(Elem([]u8) == u8);
 124    try testing.expect(Elem(*[10]u8) == u8);
 125    try testing.expect(Elem(@Vector(2, u8)) == u8);
 126    try testing.expect(Elem(*@Vector(2, u8)) == u8);
 127    try testing.expect(Elem(?[*]u8) == u8);
 128}
 129
 130/// Given a type which can have a sentinel e.g. `[:0]u8`, returns the sentinel value,
 131/// or `null` if there is not one.
 132/// Types which cannot possibly have a sentinel will be a compile error.
 133/// Result is always comptime-known.
 134pub inline fn sentinel(comptime T: type) ?Elem(T) {
 135    switch (@typeInfo(T)) {
 136        .array => |info| return info.sentinel(),
 137        .pointer => |info| {
 138            switch (info.size) {
 139                .many, .slice => return info.sentinel(),
 140                .one => switch (@typeInfo(info.child)) {
 141                    .array => |array_info| return array_info.sentinel(),
 142                    else => {},
 143                },
 144                else => {},
 145            }
 146        },
 147        else => {},
 148    }
 149    @compileError("type '" ++ @typeName(T) ++ "' cannot possibly have a sentinel");
 150}
 151
 152test sentinel {
 153    try testSentinel();
 154    try comptime testSentinel();
 155}
 156
 157fn testSentinel() !void {
 158    try testing.expectEqual(@as(u8, 0), sentinel([:0]u8).?);
 159    try testing.expectEqual(@as(u8, 0), sentinel([*:0]u8).?);
 160    try testing.expectEqual(@as(u8, 0), sentinel([5:0]u8).?);
 161    try testing.expectEqual(@as(u8, 0), sentinel(*const [5:0]u8).?);
 162
 163    try testing.expect(sentinel([]u8) == null);
 164    try testing.expect(sentinel([*]u8) == null);
 165    try testing.expect(sentinel([5]u8) == null);
 166    try testing.expect(sentinel(*const [5]u8) == null);
 167}
 168
 169/// Given a "memory span" type, returns the same type except with the given sentinel value.
 170pub fn Sentinel(comptime T: type, comptime sentinel_val: Elem(T)) type {
 171    switch (@typeInfo(T)) {
 172        .pointer => |info| switch (info.size) {
 173            .one => switch (@typeInfo(info.child)) {
 174                .array => |array_info| return @Pointer(.one, .{
 175                    .@"const" = info.is_const,
 176                    .@"volatile" = info.is_volatile,
 177                    .@"allowzero" = info.is_allowzero,
 178                    .@"align" = info.alignment,
 179                    .@"addrspace" = info.address_space,
 180                }, [array_info.len:sentinel_val]array_info.child, null),
 181                else => {},
 182            },
 183            .many, .slice => |size| return @Pointer(size, .{
 184                .@"const" = info.is_const,
 185                .@"volatile" = info.is_volatile,
 186                .@"allowzero" = info.is_allowzero,
 187                .@"align" = info.alignment,
 188                .@"addrspace" = info.address_space,
 189            }, info.child, sentinel_val),
 190            else => {},
 191        },
 192        .optional => |info| switch (@typeInfo(info.child)) {
 193            .pointer => |ptr_info| switch (ptr_info.size) {
 194                .many => return ?@Pointer(.many, .{
 195                    .@"const" = ptr_info.is_const,
 196                    .@"volatile" = ptr_info.is_volatile,
 197                    .@"allowzero" = ptr_info.is_allowzero,
 198                    .@"align" = ptr_info.alignment,
 199                    .@"addrspace" = ptr_info.address_space,
 200                    .child = ptr_info.child,
 201                }, ptr_info.child, sentinel_val),
 202                else => {},
 203            },
 204            else => {},
 205        },
 206        else => {},
 207    }
 208    @compileError("Unable to derive a sentinel pointer type from " ++ @typeName(T));
 209}
 210
 211pub fn containerLayout(comptime T: type) Type.ContainerLayout {
 212    return switch (@typeInfo(T)) {
 213        .@"struct" => |info| info.layout,
 214        .@"union" => |info| info.layout,
 215        else => @compileError("expected struct or union type, found '" ++ @typeName(T) ++ "'"),
 216    };
 217}
 218
 219test containerLayout {
 220    const S1 = struct {};
 221    const S2 = packed struct {};
 222    const S3 = extern struct {};
 223    const U1 = union {
 224        a: u8,
 225    };
 226    const U2 = packed union {
 227        a: u8,
 228    };
 229    const U3 = extern union {
 230        a: u8,
 231    };
 232
 233    try testing.expect(containerLayout(S1) == .auto);
 234    try testing.expect(containerLayout(S2) == .@"packed");
 235    try testing.expect(containerLayout(S3) == .@"extern");
 236    try testing.expect(containerLayout(U1) == .auto);
 237    try testing.expect(containerLayout(U2) == .@"packed");
 238    try testing.expect(containerLayout(U3) == .@"extern");
 239}
 240
 241/// Instead of this function, prefer to use e.g. `@typeInfo(foo).@"struct".decls`
 242/// directly when you know what kind of type it is.
 243pub fn declarations(comptime T: type) []const Type.Declaration {
 244    return switch (@typeInfo(T)) {
 245        .@"struct" => |info| info.decls,
 246        .@"enum" => |info| info.decls,
 247        .@"union" => |info| info.decls,
 248        .@"opaque" => |info| info.decls,
 249        else => @compileError("Expected struct, enum, union, or opaque type, found '" ++ @typeName(T) ++ "'"),
 250    };
 251}
 252
 253test declarations {
 254    const E1 = enum {
 255        A,
 256
 257        pub fn a() void {}
 258    };
 259    const S1 = struct {
 260        pub fn a() void {}
 261    };
 262    const U1 = union {
 263        b: u8,
 264
 265        pub fn a() void {}
 266    };
 267    const O1 = opaque {
 268        pub fn a() void {}
 269    };
 270
 271    const decls = comptime [_][]const Type.Declaration{
 272        declarations(E1),
 273        declarations(S1),
 274        declarations(U1),
 275        declarations(O1),
 276    };
 277
 278    inline for (decls) |decl| {
 279        try testing.expect(decl.len == 1);
 280        try testing.expect(comptime mem.eql(u8, decl[0].name, "a"));
 281    }
 282}
 283
 284pub fn declarationInfo(comptime T: type, comptime decl_name: []const u8) Type.Declaration {
 285    inline for (comptime declarations(T)) |decl| {
 286        if (comptime mem.eql(u8, decl.name, decl_name))
 287            return decl;
 288    }
 289
 290    @compileError("'" ++ @typeName(T) ++ "' has no declaration '" ++ decl_name ++ "'");
 291}
 292
 293test declarationInfo {
 294    const E1 = enum {
 295        A,
 296
 297        pub fn a() void {}
 298    };
 299    const S1 = struct {
 300        pub fn a() void {}
 301    };
 302    const U1 = union {
 303        b: u8,
 304
 305        pub fn a() void {}
 306    };
 307
 308    const infos = comptime [_]Type.Declaration{
 309        declarationInfo(E1, "a"),
 310        declarationInfo(S1, "a"),
 311        declarationInfo(U1, "a"),
 312    };
 313
 314    inline for (infos) |info| {
 315        try testing.expect(comptime mem.eql(u8, info.name, "a"));
 316    }
 317}
 318pub fn fields(comptime T: type) switch (@typeInfo(T)) {
 319    .@"struct" => []const Type.StructField,
 320    .@"union" => []const Type.UnionField,
 321    .@"enum" => []const Type.EnumField,
 322    .error_set => []const Type.Error,
 323    else => @compileError("Expected struct, union, error set or enum type, found '" ++ @typeName(T) ++ "'"),
 324} {
 325    return switch (@typeInfo(T)) {
 326        .@"struct" => |info| info.fields,
 327        .@"union" => |info| info.fields,
 328        .@"enum" => |info| info.fields,
 329        .error_set => |errors| errors.?, // must be non global error set
 330        else => @compileError("Expected struct, union, error set or enum type, found '" ++ @typeName(T) ++ "'"),
 331    };
 332}
 333
 334test fields {
 335    const E1 = enum {
 336        A,
 337    };
 338    const E2 = error{A};
 339    const S1 = struct {
 340        a: u8,
 341    };
 342    const U1 = union {
 343        a: u8,
 344    };
 345
 346    const e1f = comptime fields(E1);
 347    const e2f = comptime fields(E2);
 348    const sf = comptime fields(S1);
 349    const uf = comptime fields(U1);
 350
 351    try testing.expect(e1f.len == 1);
 352    try testing.expect(e2f.len == 1);
 353    try testing.expect(sf.len == 1);
 354    try testing.expect(uf.len == 1);
 355    try testing.expect(mem.eql(u8, e1f[0].name, "A"));
 356    try testing.expect(mem.eql(u8, e2f[0].name, "A"));
 357    try testing.expect(mem.eql(u8, sf[0].name, "a"));
 358    try testing.expect(mem.eql(u8, uf[0].name, "a"));
 359    try testing.expect(comptime sf[0].type == u8);
 360    try testing.expect(comptime uf[0].type == u8);
 361}
 362
 363pub fn fieldInfo(comptime T: type, comptime field: FieldEnum(T)) switch (@typeInfo(T)) {
 364    .@"struct" => Type.StructField,
 365    .@"union" => Type.UnionField,
 366    .@"enum" => Type.EnumField,
 367    .error_set => Type.Error,
 368    else => @compileError("Expected struct, union, error set or enum type, found '" ++ @typeName(T) ++ "'"),
 369} {
 370    return fields(T)[@intFromEnum(field)];
 371}
 372
 373test fieldInfo {
 374    const E1 = enum {
 375        A,
 376    };
 377    const E2 = error{A};
 378    const S1 = struct {
 379        a: u8,
 380    };
 381    const U1 = union {
 382        a: u8,
 383    };
 384
 385    const e1f = fieldInfo(E1, .A);
 386    const e2f = fieldInfo(E2, .A);
 387    const sf = fieldInfo(S1, .a);
 388    const uf = fieldInfo(U1, .a);
 389
 390    try testing.expect(mem.eql(u8, e1f.name, "A"));
 391    try testing.expect(mem.eql(u8, e2f.name, "A"));
 392    try testing.expect(mem.eql(u8, sf.name, "a"));
 393    try testing.expect(mem.eql(u8, uf.name, "a"));
 394    try testing.expect(comptime sf.type == u8);
 395    try testing.expect(comptime uf.type == u8);
 396}
 397
 398pub fn fieldNames(comptime T: type) *const [fields(T).len][:0]const u8 {
 399    return comptime blk: {
 400        const fieldInfos = fields(T);
 401        var names: [fieldInfos.len][:0]const u8 = undefined;
 402        for (&names, fieldInfos) |*name, field| name.* = field.name;
 403        const final = names;
 404        break :blk &final;
 405    };
 406}
 407
 408test fieldNames {
 409    const E1 = enum { A, B };
 410    const E2 = error{A};
 411    const S1 = struct {
 412        a: u8,
 413    };
 414    const U1 = union {
 415        a: u8,
 416        b: void,
 417    };
 418
 419    const e1names = fieldNames(E1);
 420    const e2names = fieldNames(E2);
 421    const s1names = fieldNames(S1);
 422    const u1names = fieldNames(U1);
 423
 424    try testing.expect(e1names.len == 2);
 425    try testing.expectEqualSlices(u8, e1names[0], "A");
 426    try testing.expectEqualSlices(u8, e1names[1], "B");
 427    try testing.expect(e2names.len == 1);
 428    try testing.expectEqualSlices(u8, e2names[0], "A");
 429    try testing.expect(s1names.len == 1);
 430    try testing.expectEqualSlices(u8, s1names[0], "a");
 431    try testing.expect(u1names.len == 2);
 432    try testing.expectEqualSlices(u8, u1names[0], "a");
 433    try testing.expectEqualSlices(u8, u1names[1], "b");
 434}
 435
 436/// Given an enum or error set type, returns a pointer to an array containing all tags for that
 437/// enum or error set.
 438pub fn tags(comptime T: type) *const [fields(T).len]T {
 439    return comptime blk: {
 440        const fieldInfos = fields(T);
 441        var res: [fieldInfos.len]T = undefined;
 442        for (fieldInfos, 0..) |field, i| {
 443            res[i] = @field(T, field.name);
 444        }
 445        const final = res;
 446        break :blk &final;
 447    };
 448}
 449
 450test tags {
 451    const E1 = enum { A, B };
 452    const E2 = error{A};
 453
 454    const e1_tags = tags(E1);
 455    const e2_tags = tags(E2);
 456
 457    try testing.expect(e1_tags.len == 2);
 458    try testing.expectEqual(E1.A, e1_tags[0]);
 459    try testing.expectEqual(E1.B, e1_tags[1]);
 460    try testing.expect(e2_tags.len == 1);
 461    try testing.expectEqual(E2.A, e2_tags[0]);
 462}
 463
 464/// Returns an enum with a variant named after each field of `T`.
 465pub fn FieldEnum(comptime T: type) type {
 466    const field_names = fieldNames(T);
 467
 468    switch (@typeInfo(T)) {
 469        .@"union" => |@"union"| if (@"union".tag_type) |EnumTag| {
 470            for (std.enums.values(EnumTag), 0..) |v, i| {
 471                if (@intFromEnum(v) != i) break; // enum values not consecutive
 472                if (!std.mem.eql(u8, @tagName(v), field_names[i])) break; // fields out of order
 473            } else {
 474                return EnumTag;
 475            }
 476        },
 477        else => {},
 478    }
 479
 480    const IntTag = std.math.IntFittingRange(0, field_names.len -| 1);
 481    return @Enum(IntTag, .exhaustive, field_names, &std.simd.iota(IntTag, field_names.len));
 482}
 483
 484fn expectEqualEnum(expected: anytype, actual: @TypeOf(expected)) !void {
 485    // TODO: https://github.com/ziglang/zig/issues/7419
 486    // testing.expectEqual(@typeInfo(expected).@"enum", @typeInfo(actual).@"enum");
 487    try testing.expectEqual(
 488        @typeInfo(expected).@"enum".tag_type,
 489        @typeInfo(actual).@"enum".tag_type,
 490    );
 491    // For comparing decls and fields, we cannot use the meta eql function here
 492    // because the language does not guarantee that the slice pointers for field names
 493    // and decl names will be the same.
 494    comptime {
 495        const expected_fields = @typeInfo(expected).@"enum".fields;
 496        const actual_fields = @typeInfo(actual).@"enum".fields;
 497        if (expected_fields.len != actual_fields.len) return error.FailedTest;
 498        for (expected_fields, 0..) |expected_field, i| {
 499            const actual_field = actual_fields[i];
 500            try testing.expectEqual(expected_field.value, actual_field.value);
 501            try testing.expectEqualStrings(expected_field.name, actual_field.name);
 502        }
 503    }
 504    comptime {
 505        const expected_decls = @typeInfo(expected).@"enum".decls;
 506        const actual_decls = @typeInfo(actual).@"enum".decls;
 507        if (expected_decls.len != actual_decls.len) return error.FailedTest;
 508        for (expected_decls, 0..) |expected_decl, i| {
 509            const actual_decl = actual_decls[i];
 510            try testing.expectEqualStrings(expected_decl.name, actual_decl.name);
 511        }
 512    }
 513    try testing.expectEqual(
 514        @typeInfo(expected).@"enum".is_exhaustive,
 515        @typeInfo(actual).@"enum".is_exhaustive,
 516    );
 517}
 518
 519test FieldEnum {
 520    try expectEqualEnum(enum {}, FieldEnum(struct {}));
 521    try expectEqualEnum(enum { a }, FieldEnum(struct { a: u8 }));
 522    try expectEqualEnum(enum { a, b, c }, FieldEnum(struct { a: u8, b: void, c: f32 }));
 523    try expectEqualEnum(enum { a, b, c }, FieldEnum(union { a: u8, b: void, c: f32 }));
 524
 525    const Tagged = union(enum) { a: u8, b: void, c: f32 };
 526    try testing.expectEqual(Tag(Tagged), FieldEnum(Tagged));
 527
 528    const Tag2 = enum { a, b, c };
 529    const Tagged2 = union(Tag2) { a: u8, b: void, c: f32 };
 530    try testing.expect(Tag(Tagged2) == FieldEnum(Tagged2));
 531
 532    const Tag3 = enum(u8) { a, b, c = 7 };
 533    const Tagged3 = union(Tag3) { a: u8, b: void, c: f32 };
 534    try testing.expect(Tag(Tagged3) != FieldEnum(Tagged3));
 535}
 536
 537pub fn DeclEnum(comptime T: type) type {
 538    const decls = declarations(T);
 539    var names: [decls.len][]const u8 = undefined;
 540    for (&names, decls) |*name, decl| name.* = decl.name;
 541    const IntTag = std.math.IntFittingRange(0, decls.len -| 1);
 542    return @Enum(IntTag, .exhaustive, &names, &std.simd.iota(IntTag, decls.len));
 543}
 544
 545test DeclEnum {
 546    const A = struct {
 547        pub const a: u8 = 0;
 548    };
 549    const B = union {
 550        foo: void,
 551
 552        pub const a: u8 = 0;
 553        pub const b: void = {};
 554        pub const c: f32 = 0;
 555    };
 556    const C = enum {
 557        bar,
 558
 559        pub const a: u8 = 0;
 560        pub const b: void = {};
 561        pub const c: f32 = 0;
 562    };
 563    const D = struct {};
 564
 565    try expectEqualEnum(enum { a }, DeclEnum(A));
 566    try expectEqualEnum(enum { a, b, c }, DeclEnum(B));
 567    try expectEqualEnum(enum { a, b, c }, DeclEnum(C));
 568    try expectEqualEnum(enum {}, DeclEnum(D));
 569}
 570
 571pub fn Tag(comptime T: type) type {
 572    return switch (@typeInfo(T)) {
 573        .@"enum" => |info| info.tag_type,
 574        .@"union" => |info| info.tag_type orelse @compileError(@typeName(T) ++ " has no tag type"),
 575        else => @compileError("expected enum or union type, found '" ++ @typeName(T) ++ "'"),
 576    };
 577}
 578
 579test Tag {
 580    const E = enum(u8) {
 581        C = 33,
 582        D,
 583    };
 584    const U = union(E) {
 585        C: u8,
 586        D: u16,
 587    };
 588
 589    try testing.expect(Tag(E) == u8);
 590    try testing.expect(Tag(U) == E);
 591}
 592
 593/// Returns the active tag of a tagged union
 594pub fn activeTag(u: anytype) Tag(@TypeOf(u)) {
 595    const T = @TypeOf(u);
 596    return @as(Tag(T), u);
 597}
 598
 599test activeTag {
 600    const UE = enum {
 601        Int,
 602        Float,
 603    };
 604
 605    const U = union(UE) {
 606        Int: u32,
 607        Float: f32,
 608    };
 609
 610    var u = U{ .Int = 32 };
 611    try testing.expect(activeTag(u) == UE.Int);
 612
 613    u = U{ .Float = 112.9876 };
 614    try testing.expect(activeTag(u) == UE.Float);
 615}
 616
 617/// Deprecated: Use @FieldType(U, tag_name)
 618const TagPayloadType = TagPayload;
 619
 620/// Deprecated: Use @FieldType(U, tag_name)
 621pub fn TagPayloadByName(comptime U: type, comptime tag_name: []const u8) type {
 622    const info = @typeInfo(U).@"union";
 623
 624    inline for (info.fields) |field_info| {
 625        if (comptime mem.eql(u8, field_info.name, tag_name))
 626            return field_info.type;
 627    }
 628
 629    @compileError("no field '" ++ tag_name ++ "' in union '" ++ @typeName(U) ++ "'");
 630}
 631
 632/// Deprecated: Use @FieldType(U, @tagName(tag))
 633pub fn TagPayload(comptime U: type, comptime tag: Tag(U)) type {
 634    return TagPayloadByName(U, @tagName(tag));
 635}
 636
 637test TagPayload {
 638    const Event = union(enum) {
 639        Moved: struct {
 640            from: i32,
 641            to: i32,
 642        },
 643    };
 644    const MovedEvent = TagPayload(Event, Event.Moved);
 645    const e: Event = .{ .Moved = undefined };
 646    try testing.expect(MovedEvent == @TypeOf(e.Moved));
 647}
 648
 649/// Compares two of any type for equality. Containers that do not support comparison
 650/// on their own are compared on a field-by-field basis. Pointers are not followed.
 651pub fn eql(a: anytype, b: @TypeOf(a)) bool {
 652    const T = @TypeOf(a);
 653
 654    switch (@typeInfo(T)) {
 655        .@"struct" => |info| {
 656            if (info.layout == .@"packed") return a == b;
 657
 658            inline for (info.fields) |field_info| {
 659                if (!eql(@field(a, field_info.name), @field(b, field_info.name))) return false;
 660            }
 661            return true;
 662        },
 663        .error_union => {
 664            if (a) |a_p| {
 665                if (b) |b_p| return eql(a_p, b_p) else |_| return false;
 666            } else |a_e| {
 667                if (b) |_| return false else |b_e| return a_e == b_e;
 668            }
 669        },
 670        .@"union" => |info| {
 671            if (info.tag_type) |UnionTag| {
 672                const tag_a: UnionTag = a;
 673                const tag_b: UnionTag = b;
 674                if (tag_a != tag_b) return false;
 675
 676                return switch (a) {
 677                    inline else => |val, tag| return eql(val, @field(b, @tagName(tag))),
 678                };
 679            }
 680
 681            @compileError("cannot compare untagged union type " ++ @typeName(T));
 682        },
 683        .array => {
 684            if (a.len != b.len) return false;
 685            for (a, 0..) |e, i|
 686                if (!eql(e, b[i])) return false;
 687            return true;
 688        },
 689        .vector => return @reduce(.And, a == b),
 690        .pointer => |info| {
 691            return switch (info.size) {
 692                .one, .many, .c => a == b,
 693                .slice => a.ptr == b.ptr and a.len == b.len,
 694            };
 695        },
 696        .optional => {
 697            if (a == null and b == null) return true;
 698            if (a == null or b == null) return false;
 699            return eql(a.?, b.?);
 700        },
 701        else => return a == b,
 702    }
 703}
 704
 705test eql {
 706    const S = struct {
 707        a: u32,
 708        b: f64,
 709        c: [5]u8,
 710    };
 711
 712    const U = union(enum) {
 713        s: S,
 714        f: ?f32,
 715    };
 716
 717    const s_1 = S{
 718        .a = 134,
 719        .b = 123.3,
 720        .c = "12345".*,
 721    };
 722
 723    var s_3 = S{
 724        .a = 134,
 725        .b = 123.3,
 726        .c = "12345".*,
 727    };
 728
 729    const u_1 = U{ .f = 24 };
 730    const u_2 = U{ .s = s_1 };
 731    const u_3 = U{ .f = 24 };
 732
 733    try testing.expect(eql(s_1, s_3));
 734    try testing.expect(eql(&s_1, &s_1));
 735    try testing.expect(!eql(&s_1, &s_3));
 736    try testing.expect(eql(u_1, u_3));
 737    try testing.expect(!eql(u_1, u_2));
 738
 739    const a1 = "abcdef".*;
 740    const a2 = "abcdef".*;
 741    const a3 = "ghijkl".*;
 742
 743    try testing.expect(eql(a1, a2));
 744    try testing.expect(!eql(a1, a3));
 745
 746    const EU = struct {
 747        fn tst(err: bool) !u8 {
 748            if (err) return error.Error;
 749            return @as(u8, 5);
 750        }
 751    };
 752
 753    try testing.expect(eql(EU.tst(true), EU.tst(true)));
 754    try testing.expect(eql(EU.tst(false), EU.tst(false)));
 755    try testing.expect(!eql(EU.tst(false), EU.tst(true)));
 756
 757    const CU = union(enum) {
 758        a: void,
 759        b: void,
 760        c: comptime_int,
 761    };
 762
 763    try testing.expect(eql(CU{ .a = {} }, .a));
 764    try testing.expect(!eql(CU{ .a = {} }, .b));
 765
 766    if (builtin.cpu.arch == .hexagon) return error.SkipZigTest;
 767
 768    const V = @Vector(4, u32);
 769    const v1: V = @splat(1);
 770    const v2: V = @splat(1);
 771    const v3: V = @splat(2);
 772
 773    try testing.expect(eql(v1, v2));
 774    try testing.expect(!eql(v1, v3));
 775}
 776
 777/// Deprecated: use `std.enums.fromInt` instead and handle null.
 778pub const IntToEnumError = error{InvalidEnumTag};
 779
 780/// Deprecated: use `std.enums.fromInt` instead and handle null instead of an error.
 781pub fn intToEnum(comptime EnumTag: type, tag_int: anytype) IntToEnumError!EnumTag {
 782    return std.enums.fromInt(EnumTag, tag_int) orelse return error.InvalidEnumTag;
 783}
 784
 785/// Given a type and a name, return the field index according to source order.
 786/// Returns `null` if the field is not found.
 787pub fn fieldIndex(comptime T: type, comptime name: []const u8) ?comptime_int {
 788    inline for (fields(T), 0..) |field, i| {
 789        if (mem.eql(u8, field.name, name))
 790            return i;
 791    }
 792    return null;
 793}
 794
 795/// Returns a slice of pointers to public declarations of a namespace.
 796pub fn declList(comptime Namespace: type, comptime Decl: type) []const *const Decl {
 797    const S = struct {
 798        fn declNameLessThan(context: void, lhs: *const Decl, rhs: *const Decl) bool {
 799            _ = context;
 800            return mem.lessThan(u8, lhs.name, rhs.name);
 801        }
 802    };
 803    comptime {
 804        const decls = declarations(Namespace);
 805        var array: [decls.len]*const Decl = undefined;
 806        for (decls, 0..) |decl, i| {
 807            array[i] = &@field(Namespace, decl.name);
 808        }
 809        mem.sort(*const Decl, &array, {}, S.declNameLessThan);
 810        return &array;
 811    }
 812}
 813
 814/// Deprecated: use @Int
 815pub fn Int(comptime signedness: std.builtin.Signedness, comptime bit_count: u16) type {
 816    return @Int(signedness, bit_count);
 817}
 818
 819pub fn Float(comptime bit_count: u8) type {
 820    return switch (bit_count) {
 821        16 => f16,
 822        32 => f32,
 823        64 => f64,
 824        80 => f80,
 825        128 => f128,
 826        else => @compileError("invalid float bit count"),
 827    };
 828}
 829test Float {
 830    try testing.expectEqual(f16, Float(16));
 831    try testing.expectEqual(f32, Float(32));
 832    try testing.expectEqual(f64, Float(64));
 833    try testing.expectEqual(f80, Float(80));
 834    try testing.expectEqual(f128, Float(128));
 835}
 836
 837/// For a given function type, returns a tuple type which fields will
 838/// correspond to the argument types.
 839///
 840/// Examples:
 841/// - `ArgsTuple(fn () void)` ⇒ `tuple { }`
 842/// - `ArgsTuple(fn (a: u32) u32)` ⇒ `tuple { u32 }`
 843/// - `ArgsTuple(fn (a: u32, b: f16) noreturn)` ⇒ `tuple { u32, f16 }`
 844pub fn ArgsTuple(comptime Function: type) type {
 845    const info = @typeInfo(Function);
 846    if (info != .@"fn")
 847        @compileError("ArgsTuple expects a function type");
 848
 849    const function_info = info.@"fn";
 850    if (function_info.is_var_args)
 851        @compileError("Cannot create ArgsTuple for variadic function");
 852
 853    var argument_field_list: [function_info.params.len]type = undefined;
 854    inline for (function_info.params, 0..) |arg, i| {
 855        const T = arg.type orelse @compileError("cannot create ArgsTuple for function with an 'anytype' parameter");
 856        argument_field_list[i] = T;
 857    }
 858
 859    return Tuple(&argument_field_list);
 860}
 861
 862/// Deprecated; use `@Tuple` instead.
 863///
 864/// To be removed after Zig 0.16.0 releases.
 865pub fn Tuple(comptime types: []const type) type {
 866    return @Tuple(types);
 867}
 868
 869const TupleTester = struct {
 870    fn assertTypeEqual(comptime Expected: type, comptime Actual: type) void {
 871        if (Expected != Actual)
 872            @compileError("Expected type " ++ @typeName(Expected) ++ ", but got type " ++ @typeName(Actual));
 873    }
 874
 875    fn assertTuple(comptime expected: anytype, comptime Actual: type) void {
 876        const info = @typeInfo(Actual);
 877        if (info != .@"struct")
 878            @compileError("Expected struct type");
 879        if (!info.@"struct".is_tuple)
 880            @compileError("Struct type must be a tuple type");
 881
 882        const fields_list = std.meta.fields(Actual);
 883        if (expected.len != fields_list.len)
 884            @compileError("Argument count mismatch");
 885
 886        inline for (fields_list, 0..) |fld, i| {
 887            if (expected[i] != fld.type) {
 888                @compileError("Field " ++ fld.name ++ " expected to be type " ++ @typeName(expected[i]) ++ ", but was type " ++ @typeName(fld.type));
 889            }
 890        }
 891    }
 892};
 893
 894test ArgsTuple {
 895    TupleTester.assertTuple(.{}, ArgsTuple(fn () void));
 896    TupleTester.assertTuple(.{u32}, ArgsTuple(fn (a: u32) []const u8));
 897    TupleTester.assertTuple(.{ u32, f16 }, ArgsTuple(fn (a: u32, b: f16) noreturn));
 898    TupleTester.assertTuple(.{ u32, f16, []const u8, void }, ArgsTuple(fn (a: u32, b: f16, c: []const u8, void) noreturn));
 899    TupleTester.assertTuple(.{u32}, ArgsTuple(fn (comptime a: u32) []const u8));
 900}
 901
 902test Tuple {
 903    TupleTester.assertTuple(.{}, Tuple(&[_]type{}));
 904    TupleTester.assertTuple(.{u32}, Tuple(&[_]type{u32}));
 905    TupleTester.assertTuple(.{ u32, f16 }, Tuple(&[_]type{ u32, f16 }));
 906    TupleTester.assertTuple(.{ u32, f16, []const u8, void }, Tuple(&[_]type{ u32, f16, []const u8, void }));
 907}
 908
 909test "Tuple deduplication" {
 910    const T1 = std.meta.Tuple(&.{ u32, f32, i8 });
 911    const T2 = std.meta.Tuple(&.{ u32, f32, i8 });
 912    const T3 = std.meta.Tuple(&.{ u32, f32, i7 });
 913
 914    if (T1 != T2) {
 915        @compileError("std.meta.Tuple doesn't deduplicate tuple types.");
 916    }
 917    if (T1 == T3) {
 918        @compileError("std.meta.Tuple fails to generate different types.");
 919    }
 920}
 921
 922test "ArgsTuple forwarding" {
 923    const T1 = std.meta.Tuple(&.{ u32, f32, i8 });
 924    const T2 = std.meta.ArgsTuple(fn (u32, f32, i8) void);
 925    const T3 = std.meta.ArgsTuple(fn (u32, f32, i8) callconv(.c) noreturn);
 926
 927    if (T1 != T2) {
 928        @compileError("std.meta.ArgsTuple produces different types than std.meta.Tuple");
 929    }
 930    if (T1 != T3) {
 931        @compileError("std.meta.ArgsTuple produces different types for the same argument lists.");
 932    }
 933}
 934
 935/// Returns whether `error_union` contains an error.
 936pub fn isError(error_union: anytype) bool {
 937    return if (error_union) |_| false else |_| true;
 938}
 939
 940test isError {
 941    try std.testing.expect(isError(math.divTrunc(u8, 5, 0)));
 942    try std.testing.expect(!isError(math.divTrunc(u8, 5, 5)));
 943}
 944
 945/// Returns true if a type has a namespace and the namespace contains `name`;
 946/// `false` otherwise. Result is always comptime-known.
 947pub inline fn hasFn(comptime T: type, comptime name: []const u8) bool {
 948    switch (@typeInfo(T)) {
 949        .@"struct", .@"union", .@"enum", .@"opaque" => {},
 950        else => return false,
 951    }
 952    if (!@hasDecl(T, name))
 953        return false;
 954
 955    return @typeInfo(@TypeOf(@field(T, name))) == .@"fn";
 956}
 957
 958test hasFn {
 959    const S1 = struct {
 960        pub fn foo() void {}
 961    };
 962
 963    try std.testing.expect(hasFn(S1, "foo"));
 964    try std.testing.expect(!hasFn(S1, "bar"));
 965    try std.testing.expect(!hasFn(*S1, "foo"));
 966
 967    const S2 = struct {
 968        foo: fn () void,
 969    };
 970
 971    try std.testing.expect(!hasFn(S2, "foo"));
 972}
 973
 974/// Returns true if a type has a `name` method; `false` otherwise.
 975/// Result is always comptime-known.
 976pub inline fn hasMethod(comptime T: type, comptime name: []const u8) bool {
 977    return switch (@typeInfo(T)) {
 978        .pointer => |P| switch (P.size) {
 979            .one => hasFn(P.child, name),
 980            .many, .slice, .c => false,
 981        },
 982        else => hasFn(T, name),
 983    };
 984}
 985
 986test hasMethod {
 987    try std.testing.expect(!hasMethod(u32, "foo"));
 988    try std.testing.expect(!hasMethod([]u32, "len"));
 989    try std.testing.expect(!hasMethod(struct { u32, u64 }, "len"));
 990
 991    const S1 = struct {
 992        pub fn foo() void {}
 993    };
 994
 995    try std.testing.expect(hasMethod(S1, "foo"));
 996    try std.testing.expect(hasMethod(*S1, "foo"));
 997
 998    try std.testing.expect(!hasMethod(S1, "bar"));
 999    try std.testing.expect(!hasMethod(*[1]S1, "foo"));
1000    try std.testing.expect(!hasMethod(*[10]S1, "foo"));
1001    try std.testing.expect(!hasMethod([]S1, "foo"));
1002
1003    const S2 = struct {
1004        foo: fn () void,
1005    };
1006
1007    try std.testing.expect(!hasMethod(S2, "foo"));
1008
1009    const U = union {
1010        pub fn foo() void {}
1011    };
1012
1013    try std.testing.expect(hasMethod(U, "foo"));
1014    try std.testing.expect(hasMethod(*U, "foo"));
1015    try std.testing.expect(!hasMethod(U, "bar"));
1016}
1017
1018/// True if every value of the type `T` has a unique bit pattern representing it.
1019/// In other words, `T` has no unused bits and no padding.
1020/// Result is always comptime-known.
1021pub inline fn hasUniqueRepresentation(comptime T: type) bool {
1022    return switch (@typeInfo(T)) {
1023        else => false, // TODO can we know if it's true for some of these types ?
1024
1025        .@"anyframe",
1026        .@"enum",
1027        .error_set,
1028        .@"fn",
1029        => true,
1030
1031        .bool => false,
1032
1033        .int => |info| @sizeOf(T) * 8 == info.bits,
1034
1035        .pointer => |info| info.size != .slice,
1036
1037        .optional => |info| switch (@typeInfo(info.child)) {
1038            .pointer => |ptr| !ptr.is_allowzero and switch (ptr.size) {
1039                .slice, .c => false,
1040                .one, .many => true,
1041            },
1042            else => false,
1043        },
1044
1045        .array => |info| hasUniqueRepresentation(info.child),
1046
1047        .@"struct" => |info| {
1048            if (info.layout == .@"packed") return @sizeOf(T) * 8 == @bitSizeOf(T);
1049
1050            var sum_size = @as(usize, 0);
1051
1052            inline for (info.fields) |field| {
1053                if (field.is_comptime) continue;
1054                if (!hasUniqueRepresentation(field.type)) return false;
1055                sum_size += @sizeOf(field.type);
1056            }
1057
1058            return @sizeOf(T) == sum_size;
1059        },
1060
1061        .vector => |info| hasUniqueRepresentation(info.child) and
1062            @sizeOf(T) == @sizeOf(info.child) * info.len,
1063    };
1064}
1065
1066test hasUniqueRepresentation {
1067    const TestStruct1 = struct {
1068        a: u32,
1069        b: u32,
1070    };
1071
1072    try testing.expect(hasUniqueRepresentation(TestStruct1));
1073
1074    const TestStruct2 = struct {
1075        a: u32,
1076        b: u16,
1077    };
1078
1079    try testing.expect(!hasUniqueRepresentation(TestStruct2));
1080
1081    const TestStruct3 = struct {
1082        a: u32,
1083        b: u32,
1084    };
1085
1086    try testing.expect(hasUniqueRepresentation(TestStruct3));
1087
1088    const TestStruct4 = struct { a: []const u8 };
1089
1090    try testing.expect(!hasUniqueRepresentation(TestStruct4));
1091
1092    const TestStruct5 = struct { a: TestStruct4 };
1093
1094    try testing.expect(!hasUniqueRepresentation(TestStruct5));
1095
1096    const TestStruct6 = packed struct(u8) {
1097        @"0": bool,
1098        @"1": bool,
1099        @"2": bool,
1100        @"3": bool,
1101        @"4": bool,
1102        @"5": bool,
1103        @"6": bool,
1104        @"7": bool,
1105    };
1106
1107    try testing.expect(hasUniqueRepresentation(TestStruct6));
1108
1109    const TestUnion2 = extern union {
1110        a: u32,
1111        b: u16,
1112    };
1113
1114    try testing.expect(!hasUniqueRepresentation(TestUnion2));
1115
1116    const TestUnion3 = union {
1117        a: u32,
1118        b: u16,
1119    };
1120
1121    try testing.expect(!hasUniqueRepresentation(TestUnion3));
1122
1123    const TestUnion4 = union(enum) {
1124        a: u32,
1125        b: u16,
1126    };
1127
1128    try testing.expect(!hasUniqueRepresentation(TestUnion4));
1129
1130    inline for ([_]type{ i0, u8, i16, u32, i64 }) |T| {
1131        try testing.expect(hasUniqueRepresentation(T));
1132    }
1133    inline for ([_]type{ i1, u9, i17, u33, i24 }) |T| {
1134        try testing.expect(!hasUniqueRepresentation(T));
1135    }
1136
1137    try testing.expect(hasUniqueRepresentation(*u8));
1138    try testing.expect(hasUniqueRepresentation(*const u8));
1139    try testing.expect(hasUniqueRepresentation(?*u8));
1140    try testing.expect(hasUniqueRepresentation(?*const u8));
1141
1142    try testing.expect(!hasUniqueRepresentation([]u8));
1143    try testing.expect(!hasUniqueRepresentation([]const u8));
1144    try testing.expect(!hasUniqueRepresentation(?[]u8));
1145    try testing.expect(!hasUniqueRepresentation(?[]const u8));
1146
1147    try testing.expect(hasUniqueRepresentation(@Vector(std.simd.suggestVectorLength(u8) orelse 1, u8)));
1148    try testing.expect(@sizeOf(@Vector(3, u8)) == 3 or !hasUniqueRepresentation(@Vector(3, u8)));
1149
1150    const StructWithComptimeFields = struct {
1151        comptime should_be_ignored: u64 = 42,
1152        comptime should_also_be_ignored: [*:0]const u8 = "hope you're having a good day :)",
1153        field: u32,
1154    };
1155
1156    try testing.expect(hasUniqueRepresentation(StructWithComptimeFields));
1157}