Skip to content

Commit 24bfefa

Browse files
alichraghiandrewrk
authored andcommitted
std.mem.byteSwapAllFields: support untagged unions
1 parent 3034d1e commit 24bfefa

File tree

2 files changed

+32
-3
lines changed

2 files changed

+32
-3
lines changed

lib/std/mem.zig

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2150,7 +2150,7 @@ pub fn byteSwapAllFields(comptime S: type, ptr: *S) void {
21502150
} else {
21512151
byteSwapAllFields(f.type, &@field(ptr, f.name));
21522152
},
2153-
.array => byteSwapAllFields(f.type, &@field(ptr, f.name)),
2153+
.@"union", .array => byteSwapAllFields(f.type, &@field(ptr, f.name)),
21542154
.@"enum" => {
21552155
@field(ptr, f.name) = @enumFromInt(@byteSwap(@intFromEnum(@field(ptr, f.name))));
21562156
},
@@ -2164,10 +2164,25 @@ pub fn byteSwapAllFields(comptime S: type, ptr: *S) void {
21642164
}
21652165
}
21662166
},
2167+
.@"union" => |union_info| {
2168+
if (union_info.tag_type != null) {
2169+
@compileError("byteSwapAllFields expects an untagged union");
2170+
}
2171+
2172+
const first_size = @bitSizeOf(union_info.fields[0].type);
2173+
inline for (union_info.fields) |field| {
2174+
if (@bitSizeOf(field.type) != first_size) {
2175+
@compileError("Unable to byte-swap unions with varying field sizes");
2176+
}
2177+
}
2178+
2179+
const BackingInt = std.meta.Int(.unsigned, @bitSizeOf(S));
2180+
ptr.* = @bitCast(@byteSwap(@as(BackingInt, @bitCast(ptr.*))));
2181+
},
21672182
.array => {
21682183
for (ptr) |*item| {
21692184
switch (@typeInfo(@TypeOf(item.*))) {
2170-
.@"struct", .array => byteSwapAllFields(@TypeOf(item.*), item),
2185+
.@"struct", .@"union", .array => byteSwapAllFields(@TypeOf(item.*), item),
21712186
.@"enum" => {
21722187
item.* = @enumFromInt(@byteSwap(@intFromEnum(item.*)));
21732188
},
@@ -2193,6 +2208,7 @@ test byteSwapAllFields {
21932208
f3: [1]u8,
21942209
f4: bool,
21952210
f5: f32,
2211+
f6: extern union { f0: u16, f1: u16 },
21962212
};
21972213
const K = extern struct {
21982214
f0: u8,
@@ -2209,6 +2225,7 @@ test byteSwapAllFields {
22092225
.f3 = .{0x12},
22102226
.f4 = true,
22112227
.f5 = @as(f32, @bitCast(@as(u32, 0x4640e400))),
2228+
.f6 = .{ .f0 = 0x1234 },
22122229
};
22132230
var k = K{
22142231
.f0 = 0x12,
@@ -2227,6 +2244,7 @@ test byteSwapAllFields {
22272244
.f3 = .{0x12},
22282245
.f4 = true,
22292246
.f5 = @as(f32, @bitCast(@as(u32, 0x00e44046))),
2247+
.f6 = .{ .f0 = 0x3412 },
22302248
}, s);
22312249
try std.testing.expectEqual(K{
22322250
.f0 = 0x12,

lib/std/testing.zig

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,18 @@ fn expectEqualInner(comptime T: type, expected: T, actual: T) !void {
153153

154154
.@"union" => |union_info| {
155155
if (union_info.tag_type == null) {
156-
@compileError("Unable to compare untagged union values for type " ++ @typeName(@TypeOf(actual)));
156+
const first_size = @bitSizeOf(union_info.fields[0].type);
157+
inline for (union_info.fields) |field| {
158+
if (@bitSizeOf(field.type) != first_size) {
159+
@compileError("Unable to compare untagged unions with varying field sizes for type " ++ @typeName(@TypeOf(actual)));
160+
}
161+
}
162+
163+
const BackingInt = std.meta.Int(.unsigned, @bitSizeOf(T));
164+
return expectEqual(
165+
@as(BackingInt, @bitCast(expected)),
166+
@as(BackingInt, @bitCast(actual)),
167+
);
157168
}
158169

159170
const Tag = std.meta.Tag(@TypeOf(expected));

0 commit comments

Comments
 (0)