aboutsummaryrefslogtreecommitdiff
path: root/lib/std
diff options
context:
space:
mode:
Diffstat (limited to 'lib/std')
-rw-r--r--lib/std/meta.zig95
1 files changed, 71 insertions, 24 deletions
diff --git a/lib/std/meta.zig b/lib/std/meta.zig
index 13d3c574e9..492e497ff4 100644
--- a/lib/std/meta.zig
+++ b/lib/std/meta.zig
@@ -827,6 +827,46 @@ test "sizeof" {
testing.expect(sizeof(S) == 4);
}
+/// For a given function type, returns a tuple type which fields will
+/// correspond to the argument types.
+///
+/// Examples:
+/// - `ArgsTuple(fn() void)` ⇒ `tuple { }`
+/// - `ArgsTuple(fn(a: u32) u32)` ⇒ `tuple { u32 }`
+/// - `ArgsTuple(fn(a: u32, b: f16) noreturn)` ⇒ `tuple { u32, f16 }`
+pub fn ArgsTuple(comptime Function: type) type {
+ const info = @typeInfo(Function);
+ if (info != .Fn)
+ @compileError("ArgsTuple expects a function type");
+
+ const function_info = info.Fn;
+ if (function_info.is_generic)
+ @compileError("Cannot create ArgsTuple for generic function");
+ if (function_info.is_var_args)
+ @compileError("Cannot create ArgsTuple for variadic function");
+
+ var argument_field_list: [function_info.args.len]std.builtin.TypeInfo.StructField = undefined;
+ inline for (function_info.args) |arg, i| {
+ @setEvalBranchQuota(10_000);
+ var num_buf: [128]u8 = undefined;
+ argument_field_list[i] = std.builtin.TypeInfo.StructField{
+ .name = std.fmt.bufPrint(&num_buf, "{d}", .{i}) catch unreachable,
+ .field_type = arg.arg_type.?,
+ .default_value = @as(?(arg.arg_type.?), 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 = &argument_field_list,
+ },
+ });
+}
+
/// For a given anonymous list of types, returns a new tuple type
/// with those types as fields.
///
@@ -857,34 +897,41 @@ pub fn Tuple(comptime types: []const type) type {
});
}
-test "Tuple" {
- 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));
- }
+const TupleTester = 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");
+ 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");
+ 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));
- }
+ 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(&[_]type{}));
- T.assertTuple(.{u32}, Tuple(&[_]type{u32}));
- T.assertTuple(.{ u32, f16 }, Tuple(&[_]type{ u32, f16 }));
- T.assertTuple(.{ u32, f16, []const u8 }, Tuple(&[_]type{ u32, f16, []const u8 }));
+test "ArgsTuple" {
+ TupleTester.assertTuple(.{}, ArgsTuple(fn () void));
+ TupleTester.assertTuple(.{u32}, ArgsTuple(fn (a: u32) []const u8));
+ TupleTester.assertTuple(.{ u32, f16 }, ArgsTuple(fn (a: u32, b: f16) noreturn));
+ TupleTester.assertTuple(.{ u32, f16, []const u8 }, ArgsTuple(fn (a: u32, b: f16, c: []const u8) noreturn));
+}
+
+test "Tuple" {
+ TupleTester.assertTuple(.{}, Tuple(&[_]type{}));
+ TupleTester.assertTuple(.{u32}, Tuple(&[_]type{u32}));
+ TupleTester.assertTuple(.{ u32, f16 }, Tuple(&[_]type{ u32, f16 }));
+ TupleTester.assertTuple(.{ u32, f16, []const u8 }, Tuple(&[_]type{ u32, f16, []const u8 }));
}