Merge pull request #6415 from MasterQ32/args-tuple

Implements std.meta.ArgsTuple.
master
Alexandros Naskos 2020-09-29 20:28:56 +03:00 committed by GitHub
commit 3b478631fb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 71 additions and 24 deletions

View File

@ -827,6 +827,46 @@ test "sizeof" {
testing.expect(sizeof(S) == 4); 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 /// For a given anonymous list of types, returns a new tuple type
/// with those types as fields. /// with those types as fields.
/// ///
@ -857,34 +897,41 @@ pub fn Tuple(comptime types: []const type) type {
}); });
} }
test "Tuple" { const TupleTester = struct {
const T = struct { fn assertTypeEqual(comptime Expected: type, comptime Actual: type) void {
fn assertTypeEqual(comptime Expected: type, comptime Actual: type) void { if (Expected != Actual)
if (Expected != Actual) @compileError("Expected type " ++ @typeName(Expected) ++ ", but got type " ++ @typeName(Actual));
@compileError("Expected type " ++ @typeName(Expected) ++ ", but got type " ++ @typeName(Actual)); }
}
fn assertTuple(comptime expected: anytype, comptime Actual: type) void { fn assertTuple(comptime expected: anytype, comptime Actual: type) void {
const info = @typeInfo(Actual); const info = @typeInfo(Actual);
if (info != .Struct) if (info != .Struct)
@compileError("Expected struct type"); @compileError("Expected struct type");
if (!info.Struct.is_tuple) if (!info.Struct.is_tuple)
@compileError("Struct type must be a tuple type"); @compileError("Struct type must be a tuple type");
const fields_list = std.meta.fields(Actual); const fields_list = std.meta.fields(Actual);
if (expected.len != fields_list.len) if (expected.len != fields_list.len)
@compileError("Argument count mismatch"); @compileError("Argument count mismatch");
inline for (fields_list) |fld, i| { inline for (fields_list) |fld, i| {
if (expected[i] != fld.field_type) { if (expected[i] != fld.field_type) {
@compileError("Field " ++ fld.name ++ " expected to be type " ++ @typeName(expected[i]) ++ ", but was type " ++ @typeName(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{})); test "ArgsTuple" {
T.assertTuple(.{u32}, Tuple(&[_]type{u32})); TupleTester.assertTuple(.{}, ArgsTuple(fn () void));
T.assertTuple(.{ u32, f16 }, Tuple(&[_]type{ u32, f16 })); TupleTester.assertTuple(.{u32}, ArgsTuple(fn (a: u32) []const u8));
T.assertTuple(.{ u32, f16, []const u8 }, Tuple(&[_]type{ u32, f16, []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 }));
} }