| ... | @@ -888,19 +888,20 @@ pub fn Vector(comptime len: u32, comptime child: type) type { | ... | @@ -888,19 +888,20 @@ pub fn Vector(comptime len: u32, comptime child: type) type { |
| 888 | /// Given a type and value, cast the value to the type as c would. | 888 | /// Given a type and value, cast the value to the type as c would. |
| 889 | /// This is for translate-c and is not intended for general use. | 889 | /// This is for translate-c and is not intended for general use. |
| 890 | pub fn cast(comptime DestType: type, target: anytype) DestType { | 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 | switch (@typeInfo(DestType)) { | 893 | switch (@typeInfo(DestType)) { |
| 893 | .Pointer => |dest_ptr| { | 894 | .Pointer => { |
| 894 | switch (@typeInfo(TargetType)) { | 895 | switch (@typeInfo(SourceType)) { |
| 895 | .Int, .ComptimeInt => { | 896 | .Int, .ComptimeInt => { |
| 896 | return @intToPtr(DestType, target); | 897 | return @intToPtr(DestType, target); |
| 897 | }, | 898 | }, |
| 898 | .Pointer => |ptr| { | 899 | .Pointer => { |
| 899 | return @ptrCast(DestType, @alignCast(dest_ptr.alignment, target)); | 900 | return castPtr(DestType, target); |
| 900 | }, | 901 | }, |
| 901 | .Optional => |opt| { | 902 | .Optional => |opt| { |
| 902 | if (@typeInfo(opt.child) == .Pointer) { | 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 | else => {}, | 907 | else => {}, |
| ... | @@ -908,17 +909,16 @@ pub fn cast(comptime DestType: type, target: anytype) DestType { | ... | @@ -908,17 +909,16 @@ pub fn cast(comptime DestType: type, target: anytype) DestType { |
| 908 | }, | 909 | }, |
| 909 | .Optional => |dest_opt| { | 910 | .Optional => |dest_opt| { |
| 910 | if (@typeInfo(dest_opt.child) == .Pointer) { | 911 | if (@typeInfo(dest_opt.child) == .Pointer) { |
| 911 | const dest_ptr = @typeInfo(dest_opt.child).Pointer; | 912 | switch (@typeInfo(SourceType)) { |
| 912 | switch (@typeInfo(TargetType)) { | | |
| 913 | .Int, .ComptimeInt => { | 913 | .Int, .ComptimeInt => { |
| 914 | return @intToPtr(DestType, target); | 914 | return @intToPtr(DestType, target); |
| 915 | }, | 915 | }, |
| 916 | .Pointer => { | 916 | .Pointer => { |
| 917 | return @ptrCast(DestType, @alignCast(dest_ptr.alignment, target)); | 917 | return castPtr(DestType, target); |
| 918 | }, | 918 | }, |
| 919 | .Optional => |target_opt| { | 919 | .Optional => |target_opt| { |
| 920 | if (@typeInfo(target_opt.child) == .Pointer) { | 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 | else => {}, | 924 | else => {}, |
| ... | @@ -926,25 +926,25 @@ pub fn cast(comptime DestType: type, target: anytype) DestType { | ... | @@ -926,25 +926,25 @@ pub fn cast(comptime DestType: type, target: anytype) DestType { |
| 926 | } | 926 | } |
| 927 | }, | 927 | }, |
| 928 | .Enum => { | 928 | .Enum => { |
| 929 | if (@typeInfo(TargetType) == .Int or @typeInfo(TargetType) == .ComptimeInt) { | 929 | if (@typeInfo(SourceType) == .Int or @typeInfo(SourceType) == .ComptimeInt) { |
| 930 | return @intToEnum(DestType, target); | 930 | return @intToEnum(DestType, target); |
| 931 | } | 931 | } |
| 932 | }, | 932 | }, |
| 933 | .Int, .ComptimeInt => { | 933 | .Int => { |
| 934 | switch (@typeInfo(TargetType)) { | 934 | switch (@typeInfo(SourceType)) { |
| 935 | .Pointer => { | 935 | .Pointer => { |
| 936 | return @intCast(DestType, @ptrToInt(target)); | 936 | return castInt(DestType, @ptrToInt(target)); |
| 937 | }, | 937 | }, |
| 938 | .Optional => |opt| { | 938 | .Optional => |opt| { |
| 939 | if (@typeInfo(opt.child) == .Pointer) { | 939 | if (@typeInfo(opt.child) == .Pointer) { |
| 940 | return @intCast(DestType, @ptrToInt(target)); | 940 | return castInt(DestType, @ptrToInt(target)); |
| 941 | } | 941 | } |
| 942 | }, | 942 | }, |
| 943 | .Enum => { | 943 | .Enum => { |
| 944 | return @intCast(DestType, @enumToInt(target)); | 944 | return castInt(DestType, @enumToInt(target)); |
| 945 | }, | 945 | }, |
| 946 | .Int, .ComptimeInt => { | 946 | .Int => { |
| 947 | return @intCast(DestType, target); | 947 | return castInt(DestType, target); |
| 948 | }, | 948 | }, |
| 949 | else => {}, | 949 | else => {}, |
| 950 | } | 950 | } |
| ... | @@ -954,6 +954,34 @@ pub fn cast(comptime DestType: type, target: anytype) DestType { | ... | @@ -954,6 +954,34 @@ pub fn cast(comptime DestType: type, target: anytype) DestType { |
| 954 | return @as(DestType, target); | 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 | test "std.meta.cast" { | 985 | test "std.meta.cast" { |
| 958 | const E = enum(u2) { | 986 | const E = enum(u2) { |
| 959 | Zero, | 987 | Zero, |
| ... | @@ -977,6 +1005,11 @@ test "std.meta.cast" { | ... | @@ -977,6 +1005,11 @@ test "std.meta.cast" { |
| 977 | testing.expectEqual(@as(u32, 4), cast(u32, @intToPtr(?*u32, 4))); | 1005 | testing.expectEqual(@as(u32, 4), cast(u32, @intToPtr(?*u32, 4))); |
| 978 | testing.expectEqual(@as(u32, 10), cast(u32, @as(u64, 10))); | 1006 | testing.expectEqual(@as(u32, 10), cast(u32, @as(u64, 10))); |
| 979 | testing.expectEqual(@as(u8, 2), cast(u8, E.Two)); | 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 | /// Given a value returns its size as C's sizeof operator would. | 1015 | /// Given a value returns its size as C's sizeof operator would. |