| ... | ... | @@ -888,19 +888,20 @@ pub fn Vector(comptime len: u32, comptime child: type) type { |
| 888 | 888 | /// Given a type and value, cast the value to the type as c would. |
| 889 | 889 | /// This is for translate-c and is not intended for general use. |
| 890 | 890 | pub fn cast(comptime DestType: type, target: anytype) DestType { |
| 891 | | const TargetType = @TypeOf(target); |
| 891 | // this function should behave like transCCast in translate-c, except it's for macros |
| 892 | const SourceType = @TypeOf(target); |
| 892 | 893 | switch (@typeInfo(DestType)) { |
| 893 | | .Pointer => |dest_ptr| { |
| 894 | | switch (@typeInfo(TargetType)) { |
| 894 | .Pointer => { |
| 895 | switch (@typeInfo(SourceType)) { |
| 895 | 896 | .Int, .ComptimeInt => { |
| 896 | 897 | return @intToPtr(DestType, target); |
| 897 | 898 | }, |
| 898 | | .Pointer => |ptr| { |
| 899 | | return @ptrCast(DestType, @alignCast(dest_ptr.alignment, target)); |
| 899 | .Pointer => { |
| 900 | return castPtr(DestType, target); |
| 900 | 901 | }, |
| 901 | 902 | .Optional => |opt| { |
| 902 | 903 | if (@typeInfo(opt.child) == .Pointer) { |
| 903 | | return @ptrCast(DestType, @alignCast(dest_ptr.alignment, target)); |
| 904 | return castPtr(DestType, target); |
| 904 | 905 | } |
| 905 | 906 | }, |
| 906 | 907 | else => {}, |
| ... | ... | @@ -908,17 +909,16 @@ pub fn cast(comptime DestType: type, target: anytype) DestType { |
| 908 | 909 | }, |
| 909 | 910 | .Optional => |dest_opt| { |
| 910 | 911 | if (@typeInfo(dest_opt.child) == .Pointer) { |
| 911 | | const dest_ptr = @typeInfo(dest_opt.child).Pointer; |
| 912 | | switch (@typeInfo(TargetType)) { |
| 912 | switch (@typeInfo(SourceType)) { |
| 913 | 913 | .Int, .ComptimeInt => { |
| 914 | 914 | return @intToPtr(DestType, target); |
| 915 | 915 | }, |
| 916 | 916 | .Pointer => { |
| 917 | | return @ptrCast(DestType, @alignCast(dest_ptr.alignment, target)); |
| 917 | return castPtr(DestType, target); |
| 918 | 918 | }, |
| 919 | 919 | .Optional => |target_opt| { |
| 920 | 920 | if (@typeInfo(target_opt.child) == .Pointer) { |
| 921 | | return @ptrCast(DestType, @alignCast(dest_ptr.alignment, target)); |
| 921 | return castPtr(DestType, target); |
| 922 | 922 | } |
| 923 | 923 | }, |
| 924 | 924 | else => {}, |
| ... | ... | @@ -926,25 +926,25 @@ pub fn cast(comptime DestType: type, target: anytype) DestType { |
| 926 | 926 | } |
| 927 | 927 | }, |
| 928 | 928 | .Enum => { |
| 929 | | if (@typeInfo(TargetType) == .Int or @typeInfo(TargetType) == .ComptimeInt) { |
| 929 | if (@typeInfo(SourceType) == .Int or @typeInfo(SourceType) == .ComptimeInt) { |
| 930 | 930 | return @intToEnum(DestType, target); |
| 931 | 931 | } |
| 932 | 932 | }, |
| 933 | | .Int, .ComptimeInt => { |
| 934 | | switch (@typeInfo(TargetType)) { |
| 933 | .Int => { |
| 934 | switch (@typeInfo(SourceType)) { |
| 935 | 935 | .Pointer => { |
| 936 | | return @intCast(DestType, @ptrToInt(target)); |
| 936 | return castInt(DestType, @ptrToInt(target)); |
| 937 | 937 | }, |
| 938 | 938 | .Optional => |opt| { |
| 939 | 939 | if (@typeInfo(opt.child) == .Pointer) { |
| 940 | | return @intCast(DestType, @ptrToInt(target)); |
| 940 | return castInt(DestType, @ptrToInt(target)); |
| 941 | 941 | } |
| 942 | 942 | }, |
| 943 | 943 | .Enum => { |
| 944 | | return @intCast(DestType, @enumToInt(target)); |
| 944 | return castInt(DestType, @enumToInt(target)); |
| 945 | 945 | }, |
| 946 | | .Int, .ComptimeInt => { |
| 947 | | return @intCast(DestType, target); |
| 946 | .Int => { |
| 947 | return castInt(DestType, target); |
| 948 | 948 | }, |
| 949 | 949 | else => {}, |
| 950 | 950 | } |
| ... | ... | @@ -954,6 +954,34 @@ pub fn cast(comptime DestType: type, target: anytype) DestType { |
| 954 | 954 | return @as(DestType, target); |
| 955 | 955 | } |
| 956 | 956 | |
| 957 | fn castInt(comptime DestType: type, target: anytype) DestType { |
| 958 | const dest = @typeInfo(DestType).Int; |
| 959 | const source = @typeInfo(@TypeOf(target)).Int; |
| 960 | |
| 961 | if (dest.bits < source.bits) |
| 962 | return @bitCast(DestType, @truncate(Int(source.signedness, dest.bits), target)) |
| 963 | else |
| 964 | return @bitCast(DestType, @as(Int(source.signedness, dest.bits), target)); |
| 965 | } |
| 966 | |
| 967 | fn castPtr(comptime DestType: type, target: anytype) DestType { |
| 968 | const dest = ptrInfo(DestType); |
| 969 | const source = ptrInfo(@TypeOf(target)); |
| 970 | |
| 971 | if (source.is_const and !dest.is_const or source.is_volatile and !dest.is_volatile) |
| 972 | return @intToPtr(DestType, @ptrToInt(target)) |
| 973 | else |
| 974 | return @ptrCast(DestType, @alignCast(dest.alignment, target)); |
| 975 | } |
| 976 | |
| 977 | fn ptrInfo(comptime PtrType: type) TypeInfo.Pointer { |
| 978 | return switch(@typeInfo(PtrType)){ |
| 979 | .Optional => |opt_info| @typeInfo(opt_info.child).Pointer, |
| 980 | .Pointer => |ptr_info| ptr_info, |
| 981 | else => unreachable, |
| 982 | }; |
| 983 | } |
| 984 | |
| 957 | 985 | test "std.meta.cast" { |
| 958 | 986 | const E = enum(u2) { |
| 959 | 987 | Zero, |
| ... | ... | @@ -977,6 +1005,11 @@ test "std.meta.cast" { |
| 977 | 1005 | testing.expectEqual(@as(u32, 4), cast(u32, @intToPtr(?*u32, 4))); |
| 978 | 1006 | testing.expectEqual(@as(u32, 10), cast(u32, @as(u64, 10))); |
| 979 | 1007 | testing.expectEqual(@as(u8, 2), cast(u8, E.Two)); |
| 1008 | |
| 1009 | testing.expectEqual(@bitCast(i32, @as(u32, 0x8000_0000)), cast(i32, @as(u32, 0x8000_0000))); |
| 1010 | |
| 1011 | testing.expectEqual(@intToPtr(*u8, 2), cast(*u8, @intToPtr(*const u8, 2))); |
| 1012 | testing.expectEqual(@intToPtr(*u8, 2), cast(*u8, @intToPtr(*volatile u8, 2))); |
| 980 | 1013 | } |
| 981 | 1014 | |
| 982 | 1015 | /// Given a value returns its size as C's sizeof operator would. |