authorgravatar for alichraghi@proton.meAli Chraghi <alichraghi@proton.me> 2025-06-22 12:39:28+03:30
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-06-23 05:57:56+02:00
log24bfefa75e813af188e3fa43e473e495cc97ed43
tree63e1d5abe16eb67e092052e7babf2e012bb90097
parent3034d1e37738ee6f1b4e50077843c271b84828f1

std.mem.byteSwapAllFields: support untagged unions


2 files changed, 32 insertions(+), 3 deletions(-)

lib/std/mem.zig+20-2
......@@ -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+12-1
......@@ -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));