Commit 7f68b14377

Felix (xq) Queißner <git@mq32.de>
2020-09-25 09:27:00
Implements std.meta.Tuple(), implements #4607 in userland.
1 parent f8b3543
Changed files (1)
lib
lib/std/meta.zig
@@ -807,7 +807,7 @@ pub fn sizeof(target: anytype) usize {
             // TODO to get the correct result we have to translate
             // `1073741824 * 4` as `int(1073741824) *% int(4)` since
             // sizeof(1073741824 * 4) != sizeof(4294967296).
-            
+
             // TODO test if target fits in int, long or long long
             return @sizeOf(c_int);
         },
@@ -826,3 +826,65 @@ test "sizeof" {
     testing.expect(sizeof(E.One) == @sizeOf(c_int));
     testing.expect(sizeof(S) == 4);
 }
+
+/// For a given anonymous list of types, returns a new tuple type
+/// with those types as fields.
+///
+/// Examples:
+/// - `Tuple(.{})` ⇒ `tuple { }`
+/// - `Tuple(.{f32})` ⇒ `tuple { f32 }`
+/// - `Tuple(.{f32,u32})` ⇒ `tuple { f32, u32 }`
+pub fn Tuple(comptime types: anytype) type {
+    var tuple_fields: [types.len]std.builtin.TypeInfo.StructField = undefined;
+    inline for (types) |T, i| {
+        @setEvalBranchQuota(10_000);
+        var num_buf: [128]u8 = undefined;
+        tuple_fields[i] = std.builtin.TypeInfo.StructField{
+            .name = std.fmt.bufPrint(&num_buf, "{d}", .{i}) catch unreachable,
+            .field_type = T,
+            .default_value = @as(?T, null),
+            .is_comptime = false,
+        };
+    }
+
+    return @Type(std.builtin.TypeInfo{
+        .Struct = std.builtin.TypeInfo.Struct{
+            .is_tuple = true,
+            .layout = .Auto,
+            .decls = &[_]std.builtin.TypeInfo.Declaration{},
+            .fields = &tuple_fields,
+        },
+    });
+}
+
+comptime {
+    const T = struct {
+        fn assertTypeEqual(comptime Expected: type, comptime Actual: type) void {
+            if (Expected != Actual)
+                @compileError("Expected type " ++ @typeName(Expected) ++ ", but got type " ++ @typeName(Actual));
+        }
+
+        fn assertTuple(comptime expected: anytype, comptime Actual: type) void {
+            const info = @typeInfo(Actual);
+            if (info != .Struct)
+                @compileError("Expected struct type");
+            if (!info.Struct.is_tuple)
+                @compileError("Struct type must be a tuple type");
+
+            const fields_list = std.meta.fields(Actual);
+            if (expected.len != fields_list.len)
+                @compileError("Argument count mismatch");
+
+            inline for (fields_list) |fld, i| {
+                if (expected[i] != fld.field_type) {
+                    @compileError("Field " ++ fld.name ++ " expected to be type " ++ @typeName(expected[i]) ++ ", but was type " ++ @typeName(fld.field_type));
+                }
+            }
+        }
+    };
+
+    T.assertTuple(.{}, Tuple(.{}));
+    T.assertTuple(.{u32}, Tuple(.{u32}));
+    T.assertTuple(.{ u32, f16 }, Tuple(.{ u32, f16 }));
+    T.assertTuple(.{ u32, f16, []const u8 }, Tuple(.{ u32, f16, []const u8 }));
+}