translate-c: improve std.meta.cast

This commit is contained in:
xackus 2021-03-13 17:36:38 +01:00 committed by Veikka Tuominen
parent 83d0c2ed67
commit 9a94415680
2 changed files with 52 additions and 18 deletions

View File

@ -888,19 +888,20 @@ pub fn Vector(comptime len: u32, comptime child: type) type {
/// Given a type and value, cast the value to the type as c would.
/// This is for translate-c and is not intended for general use.
pub fn cast(comptime DestType: type, target: anytype) DestType {
const TargetType = @TypeOf(target);
// this function should behave like transCCast in translate-c, except it's for macros
const SourceType = @TypeOf(target);
switch (@typeInfo(DestType)) {
.Pointer => |dest_ptr| {
switch (@typeInfo(TargetType)) {
.Pointer => {
switch (@typeInfo(SourceType)) {
.Int, .ComptimeInt => {
return @intToPtr(DestType, target);
},
.Pointer => |ptr| {
return @ptrCast(DestType, @alignCast(dest_ptr.alignment, target));
.Pointer => {
return castPtr(DestType, target);
},
.Optional => |opt| {
if (@typeInfo(opt.child) == .Pointer) {
return @ptrCast(DestType, @alignCast(dest_ptr.alignment, target));
return castPtr(DestType, target);
}
},
else => {},
@ -908,17 +909,16 @@ pub fn cast(comptime DestType: type, target: anytype) DestType {
},
.Optional => |dest_opt| {
if (@typeInfo(dest_opt.child) == .Pointer) {
const dest_ptr = @typeInfo(dest_opt.child).Pointer;
switch (@typeInfo(TargetType)) {
switch (@typeInfo(SourceType)) {
.Int, .ComptimeInt => {
return @intToPtr(DestType, target);
},
.Pointer => {
return @ptrCast(DestType, @alignCast(dest_ptr.alignment, target));
return castPtr(DestType, target);
},
.Optional => |target_opt| {
if (@typeInfo(target_opt.child) == .Pointer) {
return @ptrCast(DestType, @alignCast(dest_ptr.alignment, target));
return castPtr(DestType, target);
}
},
else => {},
@ -926,25 +926,25 @@ pub fn cast(comptime DestType: type, target: anytype) DestType {
}
},
.Enum => {
if (@typeInfo(TargetType) == .Int or @typeInfo(TargetType) == .ComptimeInt) {
if (@typeInfo(SourceType) == .Int or @typeInfo(SourceType) == .ComptimeInt) {
return @intToEnum(DestType, target);
}
},
.Int, .ComptimeInt => {
switch (@typeInfo(TargetType)) {
.Int => {
switch (@typeInfo(SourceType)) {
.Pointer => {
return @intCast(DestType, @ptrToInt(target));
return castInt(DestType, @ptrToInt(target));
},
.Optional => |opt| {
if (@typeInfo(opt.child) == .Pointer) {
return @intCast(DestType, @ptrToInt(target));
return castInt(DestType, @ptrToInt(target));
}
},
.Enum => {
return @intCast(DestType, @enumToInt(target));
return castInt(DestType, @enumToInt(target));
},
.Int, .ComptimeInt => {
return @intCast(DestType, target);
.Int => {
return castInt(DestType, target);
},
else => {},
}
@ -954,6 +954,34 @@ pub fn cast(comptime DestType: type, target: anytype) DestType {
return @as(DestType, target);
}
fn castInt(comptime DestType: type, target: anytype) DestType {
const dest = @typeInfo(DestType).Int;
const source = @typeInfo(@TypeOf(target)).Int;
if (dest.bits < source.bits)
return @bitCast(DestType, @truncate(Int(source.signedness, dest.bits), target))
else
return @bitCast(DestType, @as(Int(source.signedness, dest.bits), target));
}
fn castPtr(comptime DestType: type, target: anytype) DestType {
const dest = ptrInfo(DestType);
const source = ptrInfo(@TypeOf(target));
if (source.is_const and !dest.is_const or source.is_volatile and !dest.is_volatile)
return @intToPtr(DestType, @ptrToInt(target))
else
return @ptrCast(DestType, @alignCast(dest.alignment, target));
}
fn ptrInfo(comptime PtrType: type) TypeInfo.Pointer {
return switch(@typeInfo(PtrType)){
.Optional => |opt_info| @typeInfo(opt_info.child).Pointer,
.Pointer => |ptr_info| ptr_info,
else => unreachable,
};
}
test "std.meta.cast" {
const E = enum(u2) {
Zero,
@ -977,6 +1005,11 @@ test "std.meta.cast" {
testing.expectEqual(@as(u32, 4), cast(u32, @intToPtr(?*u32, 4)));
testing.expectEqual(@as(u32, 10), cast(u32, @as(u64, 10)));
testing.expectEqual(@as(u8, 2), cast(u8, E.Two));
testing.expectEqual(@bitCast(i32, @as(u32, 0x8000_0000)), cast(i32, @as(u32, 0x8000_0000)));
testing.expectEqual(@intToPtr(*u8, 2), cast(*u8, @intToPtr(*const u8, 2)));
testing.expectEqual(@intToPtr(*u8, 2), cast(*u8, @intToPtr(*volatile u8, 2)));
}
/// Given a value returns its size as C's sizeof operator would.

View File

@ -1836,6 +1836,7 @@ fn cIntTypeForEnum(enum_qt: clang.QualType) clang.QualType {
return enum_decl.getIntegerType();
}
// when modifying this function, make sure to also update std.meta.cast
fn transCCast(
c: *Context,
scope: *Scope,