authorgravatar for xq@random-projects.netFelix "xq" Queißner <xq@random-projects.net> 2020-09-25 09:16:43+02:00
committergravatar for xq@random-projects.netFelix "xq" Queißner <xq@random-projects.net> 2020-09-25 09:16:43+02:00
log93291cc4722d51afbba7378fab5cfb25da175a79
tree05783322518685ac2ff16d00e48b9307468d6305
parentf8b3543cabc28df15e85085a72adb474b345cf93

Implements std.meta.ArgsTuple.


1 files changed, 73 insertions(+), 1 deletions(-)

lib/std/meta.zig+73-1
...@@ -807,7 +807,7 @@ pub fn sizeof(target: anytype) usize {...@@ -807,7 +807,7 @@ pub fn sizeof(target: anytype) usize {
807 // TODO to get the correct result we have to translate807 // TODO to get the correct result we have to translate
808 // `1073741824 * 4` as `int(1073741824) *% int(4)` since808 // `1073741824 * 4` as `int(1073741824) *% int(4)` since
809 // sizeof(1073741824 * 4) != sizeof(4294967296).809 // sizeof(1073741824 * 4) != sizeof(4294967296).
810 810
811 // TODO test if target fits in int, long or long long811 // TODO test if target fits in int, long or long long
812 return @sizeOf(c_int);812 return @sizeOf(c_int);
813 },813 },
...@@ -826,3 +826,75 @@ test "sizeof" {...@@ -826,3 +826,75 @@ test "sizeof" {
826 testing.expect(sizeof(E.One) == @sizeOf(c_int));826 testing.expect(sizeof(E.One) == @sizeOf(c_int));
827 testing.expect(sizeof(S) == 4);827 testing.expect(sizeof(S) == 4);
828}828}
829
830/// For a given function type, returns a tuple type which fields will
831/// correspond to the argument types.
832///
833/// Examples:
834/// - `ArgsTuple(fn() void)` ⇒ `tuple { }`
835/// - `ArgsTuple(fn(a: u32) u32)` ⇒ `tuple { u32 }`
836/// - `ArgsTuple(fn(a: u32, b: f16) noreturn)` ⇒ `tuple { u32, f16 }`
837pub fn ArgsTuple(comptime Function: type) type {
838 const info = @typeInfo(Function);
839 if (info != .Fn)
840 @compileError("ArgsTuple expects a function type");
841
842 const function_info = info.Fn;
843 if (function_info.is_generic)
844 @compileError("Cannot create ArgsTuple for generic function");
845 if (function_info.is_var_args)
846 @compileError("Cannot create ArgsTuple for variadic function");
847
848 var argument_field_list: [function_info.args.len]std.builtin.TypeInfo.StructField = undefined;
849 inline for (function_info.args) |arg, i| {
850 @setEvalBranchQuota(10_000);
851 var num_buf: [128]u8 = undefined;
852 argument_field_list[i] = std.builtin.TypeInfo.StructField{
853 .name = std.fmt.bufPrint(&num_buf, "{d}", .{i}) catch unreachable,
854 .field_type = arg.arg_type.?,
855 .default_value = @as(?(arg.arg_type.?), null),
856 .is_comptime = false,
857 };
858 }
859
860 return @Type(std.builtin.TypeInfo{
861 .Struct = std.builtin.TypeInfo.Struct{
862 .is_tuple = true,
863 .layout = .Auto,
864 .decls = &[_]std.builtin.TypeInfo.Declaration{},
865 .fields = &argument_field_list,
866 },
867 });
868}
869
870comptime {
871 const T = struct {
872 fn assertTypeEqual(comptime Expected: type, comptime Actual: type) void {
873 if (Expected != Actual)
874 @compileError("Expected type " ++ @typeName(Expected) ++ ", but got type " ++ @typeName(Actual));
875 }
876
877 fn assertTuple(comptime expected: anytype, comptime Actual: type) void {
878 const info = @typeInfo(Actual);
879 if (info != .Struct)
880 @compileError("Expected struct type");
881 if (!info.Struct.is_tuple)
882 @compileError("Struct type must be a tuple type");
883
884 const fields_list = std.meta.fields(Actual);
885 if (expected.len != fields_list.len)
886 @compileError("Argument count mismatch");
887
888 inline for (fields_list) |fld, i| {
889 if (expected[i] != fld.field_type) {
890 @compileError("Field " ++ fld.name ++ " expected to be type " ++ @typeName(expected[i]) ++ ", but was type " ++ @typeName(fld.field_type));
891 }
892 }
893 }
894 };
895
896 T.assertTuple(.{}, ArgsTuple(fn () void));
897 T.assertTuple(.{u32}, ArgsTuple(fn (a: u32) []const u8));
898 T.assertTuple(.{ u32, f16 }, ArgsTuple(fn (a: u32, b: f16) noreturn));
899 T.assertTuple(.{ u32, f16, []const u8 }, ArgsTuple(fn (a: u32, b: f16, c: []const u8) noreturn));
900}