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 {...@@ -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.
890pub fn cast(comptime DestType: type, target: anytype) DestType {890pub 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}
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
957test "std.meta.cast" {985test "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}
9811014
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.
src/translate_c.zig+1
...@@ -1836,6 +1836,7 @@ fn cIntTypeForEnum(enum_qt: clang.QualType) clang.QualType {...@@ -1836,6 +1836,7 @@ fn cIntTypeForEnum(enum_qt: clang.QualType) clang.QualType {
1836 return enum_decl.getIntegerType();1836 return enum_decl.getIntegerType();
1837}1837}
18381838
1839// when modifying this function, make sure to also update std.meta.cast
1839fn transCCast(1840fn transCCast(
1840 c: *Context,1841 c: *Context,
1841 scope: *Scope,1842 scope: *Scope,