authorgravatar for 14938807+xackus@users.noreply.github.comxackus <14938807+xackus@users.noreply.github.com> 2021-03-13 17:36:38+01:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2021-03-17 00:05:42+02:00
log9a9441568070320d6549fe286300b45ffffd7b4d
tree8010d5c3ba1164a24259ad9a6b8d9f68e2cfc1b8
parent83d0c2ed67622ba30a56da0356f4dcd23c126273

translate-c: improve std.meta.cast


2 files changed, 52 insertions(+), 18 deletions(-)

lib/std/meta.zig+51-18
......@@ -888,19 +888,20 @@ pub fn Vector(comptime len: u32, comptime child: type) type {
888888/// Given a type and value, cast the value to the type as c would.
889889/// This is for translate-c and is not intended for general use.
890890pub 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);
892893 switch (@typeInfo(DestType)) {
893 .Pointer => |dest_ptr| {
894 switch (@typeInfo(TargetType)) {
894 .Pointer => {
895 switch (@typeInfo(SourceType)) {
895896 .Int, .ComptimeInt => {
896897 return @intToPtr(DestType, target);
897898 },
898 .Pointer => |ptr| {
899 return @ptrCast(DestType, @alignCast(dest_ptr.alignment, target));
899 .Pointer => {
900 return castPtr(DestType, target);
900901 },
901902 .Optional => |opt| {
902903 if (@typeInfo(opt.child) == .Pointer) {
903 return @ptrCast(DestType, @alignCast(dest_ptr.alignment, target));
904 return castPtr(DestType, target);
904905 }
905906 },
906907 else => {},
......@@ -908,17 +909,16 @@ pub fn cast(comptime DestType: type, target: anytype) DestType {
908909 },
909910 .Optional => |dest_opt| {
910911 if (@typeInfo(dest_opt.child) == .Pointer) {
911 const dest_ptr = @typeInfo(dest_opt.child).Pointer;
912 switch (@typeInfo(TargetType)) {
912 switch (@typeInfo(SourceType)) {
913913 .Int, .ComptimeInt => {
914914 return @intToPtr(DestType, target);
915915 },
916916 .Pointer => {
917 return @ptrCast(DestType, @alignCast(dest_ptr.alignment, target));
917 return castPtr(DestType, target);
918918 },
919919 .Optional => |target_opt| {
920920 if (@typeInfo(target_opt.child) == .Pointer) {
921 return @ptrCast(DestType, @alignCast(dest_ptr.alignment, target));
921 return castPtr(DestType, target);
922922 }
923923 },
924924 else => {},
......@@ -926,25 +926,25 @@ pub fn cast(comptime DestType: type, target: anytype) DestType {
926926 }
927927 },
928928 .Enum => {
929 if (@typeInfo(TargetType) == .Int or @typeInfo(TargetType) == .ComptimeInt) {
929 if (@typeInfo(SourceType) == .Int or @typeInfo(SourceType) == .ComptimeInt) {
930930 return @intToEnum(DestType, target);
931931 }
932932 },
933 .Int, .ComptimeInt => {
934 switch (@typeInfo(TargetType)) {
933 .Int => {
934 switch (@typeInfo(SourceType)) {
935935 .Pointer => {
936 return @intCast(DestType, @ptrToInt(target));
936 return castInt(DestType, @ptrToInt(target));
937937 },
938938 .Optional => |opt| {
939939 if (@typeInfo(opt.child) == .Pointer) {
940 return @intCast(DestType, @ptrToInt(target));
940 return castInt(DestType, @ptrToInt(target));
941941 }
942942 },
943943 .Enum => {
944 return @intCast(DestType, @enumToInt(target));
944 return castInt(DestType, @enumToInt(target));
945945 },
946 .Int, .ComptimeInt => {
947 return @intCast(DestType, target);
946 .Int => {
947 return castInt(DestType, target);
948948 },
949949 else => {},
950950 }
......@@ -954,6 +954,34 @@ pub fn cast(comptime DestType: type, target: anytype) DestType {
954954 return @as(DestType, target);
955955}
956956
957fn 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
967fn 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
977fn 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
957985test "std.meta.cast" {
958986 const E = enum(u2) {
959987 Zero,
......@@ -977,6 +1005,11 @@ test "std.meta.cast" {
9771005 testing.expectEqual(@as(u32, 4), cast(u32, @intToPtr(?*u32, 4)));
9781006 testing.expectEqual(@as(u32, 10), cast(u32, @as(u64, 10)));
9791007 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)));
9801013}
9811014
9821015/// Given a value returns its size as C's sizeof operator would.
src/translate_c.zig+1
......@@ -1836,6 +1836,7 @@ fn cIntTypeForEnum(enum_qt: clang.QualType) clang.QualType {
18361836 return enum_decl.getIntegerType();
18371837}
18381838
1839// when modifying this function, make sure to also update std.meta.cast
18391840fn transCCast(
18401841 c: *Context,
18411842 scope: *Scope,