| ... | @@ -827,6 +827,46 @@ test "sizeof" { | ... | @@ -827,6 +827,46 @@ test "sizeof" { |
| 827 | testing.expect(sizeof(S) == 4); | 827 | testing.expect(sizeof(S) == 4); |
| 828 | } | 828 | } |
| 829 | | 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 }` |
| | 837 | pub 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 | |
| 830 | /// For a given anonymous list of types, returns a new tuple type | 870 | /// For a given anonymous list of types, returns a new tuple type |
| 831 | /// with those types as fields. | 871 | /// with those types as fields. |
| 832 | /// | 872 | /// |
| ... | @@ -857,34 +897,41 @@ pub fn Tuple(comptime types: []const type) type { | ... | @@ -857,34 +897,41 @@ pub fn Tuple(comptime types: []const type) type { |
| 857 | }); | 897 | }); |
| 858 | } | 898 | } |
| 859 | | 899 | |
| 860 | test "Tuple" { | 900 | const TupleTester = struct { |
| 861 | const T = struct { | 901 | fn assertTypeEqual(comptime Expected: type, comptime Actual: type) void { |
| 862 | fn assertTypeEqual(comptime Expected: type, comptime Actual: type) void { | 902 | if (Expected != Actual) |
| 863 | if (Expected != Actual) | 903 | @compileError("Expected type " ++ @typeName(Expected) ++ ", but got type " ++ @typeName(Actual)); |
| 864 | @compileError("Expected type " ++ @typeName(Expected) ++ ", but got type " ++ @typeName(Actual)); | 904 | } |
| 865 | } | | |
| 866 | | 905 | |
| 867 | fn assertTuple(comptime expected: anytype, comptime Actual: type) void { | 906 | fn assertTuple(comptime expected: anytype, comptime Actual: type) void { |
| 868 | const info = @typeInfo(Actual); | 907 | const info = @typeInfo(Actual); |
| 869 | if (info != .Struct) | 908 | if (info != .Struct) |
| 870 | @compileError("Expected struct type"); | 909 | @compileError("Expected struct type"); |
| 871 | if (!info.Struct.is_tuple) | 910 | if (!info.Struct.is_tuple) |
| 872 | @compileError("Struct type must be a tuple type"); | 911 | @compileError("Struct type must be a tuple type"); |
| 873 | | 912 | |
| 874 | const fields_list = std.meta.fields(Actual); | 913 | const fields_list = std.meta.fields(Actual); |
| 875 | if (expected.len != fields_list.len) | 914 | if (expected.len != fields_list.len) |
| 876 | @compileError("Argument count mismatch"); | 915 | @compileError("Argument count mismatch"); |
| 877 | | 916 | |
| 878 | inline for (fields_list) |fld, i| { | 917 | inline for (fields_list) |fld, i| { |
| 879 | if (expected[i] != fld.field_type) { | 918 | if (expected[i] != fld.field_type) { |
| 880 | @compileError("Field " ++ fld.name ++ " expected to be type " ++ @typeName(expected[i]) ++ ", but was type " ++ @typeName(fld.field_type)); | 919 | @compileError("Field " ++ fld.name ++ " expected to be type " ++ @typeName(expected[i]) ++ ", but was type " ++ @typeName(fld.field_type)); |
| 881 | } | | |
| 882 | } | 920 | } |
| 883 | } | 921 | } |
| 884 | }; | 922 | } |
| | 923 | }; |
| 885 | | 924 | |
| 886 | T.assertTuple(.{}, Tuple(&[_]type{})); | 925 | test "ArgsTuple" { |
| 887 | T.assertTuple(.{u32}, Tuple(&[_]type{u32})); | 926 | TupleTester.assertTuple(.{}, ArgsTuple(fn () void)); |
| 888 | T.assertTuple(.{ u32, f16 }, Tuple(&[_]type{ u32, f16 })); | 927 | TupleTester.assertTuple(.{u32}, ArgsTuple(fn (a: u32) []const u8)); |
| 889 | T.assertTuple(.{ u32, f16, []const u8 }, Tuple(&[_]type{ u32, f16, []const u8 })); | 928 | TupleTester.assertTuple(.{ u32, f16 }, ArgsTuple(fn (a: u32, b: f16) noreturn)); |
| | 929 | TupleTester.assertTuple(.{ u32, f16, []const u8 }, ArgsTuple(fn (a: u32, b: f16, c: []const u8) noreturn)); |
| | 930 | } |
| | 931 | |
| | 932 | test "Tuple" { |
| | 933 | TupleTester.assertTuple(.{}, Tuple(&[_]type{})); |
| | 934 | TupleTester.assertTuple(.{u32}, Tuple(&[_]type{u32})); |
| | 935 | TupleTester.assertTuple(.{ u32, f16 }, Tuple(&[_]type{ u32, f16 })); |
| | 936 | TupleTester.assertTuple(.{ u32, f16, []const u8 }, Tuple(&[_]type{ u32, f16, []const u8 })); |
| 890 | } | 937 | } |