diff options
| author | xackus <14938807+xackus@users.noreply.github.com> | 2021-03-13 17:36:38 +0100 |
|---|---|---|
| committer | Veikka Tuominen <git@vexu.eu> | 2021-03-17 00:05:42 +0200 |
| commit | 9a9441568070320d6549fe286300b45ffffd7b4d (patch) | |
| tree | 8010d5c3ba1164a24259ad9a6b8d9f68e2cfc1b8 /lib/std/meta.zig | |
| parent | 83d0c2ed67622ba30a56da0356f4dcd23c126273 (diff) | |
| download | zig-9a9441568070320d6549fe286300b45ffffd7b4d.tar.gz zig-9a9441568070320d6549fe286300b45ffffd7b4d.zip | |
translate-c: improve std.meta.cast
Diffstat (limited to 'lib/std/meta.zig')
| -rw-r--r-- | lib/std/meta.zig | 69 |
1 files changed, 51 insertions, 18 deletions
diff --git a/lib/std/meta.zig b/lib/std/meta.zig index fd3e03bdbd..cdc93e5d33 100644 --- a/lib/std/meta.zig +++ b/lib/std/meta.zig @@ -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. |
