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 {...@@ -2150,7 +2150,7 @@ pub fn byteSwapAllFields(comptime S: type, ptr: *S) void {
2150 } else {2150 } else {
2151 byteSwapAllFields(f.type, &@field(ptr, f.name));2151 byteSwapAllFields(f.type, &@field(ptr, f.name));
2152 },2152 },
2153 .array => byteSwapAllFields(f.type, &@field(ptr, f.name)),2153 .@"union", .array => byteSwapAllFields(f.type, &@field(ptr, f.name)),
2154 .@"enum" => {2154 .@"enum" => {
2155 @field(ptr, f.name) = @enumFromInt(@byteSwap(@intFromEnum(@field(ptr, f.name))));2155 @field(ptr, f.name) = @enumFromInt(@byteSwap(@intFromEnum(@field(ptr, f.name))));
2156 },2156 },
...@@ -2164,10 +2164,25 @@ pub fn byteSwapAllFields(comptime S: type, ptr: *S) void {...@@ -2164,10 +2164,25 @@ pub fn byteSwapAllFields(comptime S: type, ptr: *S) void {
2164 }2164 }
2165 }2165 }
2166 },2166 },
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 },
2167 .array => {2182 .array => {
2168 for (ptr) |*item| {2183 for (ptr) |*item| {
2169 switch (@typeInfo(@TypeOf(item.*))) {2184 switch (@typeInfo(@TypeOf(item.*))) {
2170 .@"struct", .array => byteSwapAllFields(@TypeOf(item.*), item),2185 .@"struct", .@"union", .array => byteSwapAllFields(@TypeOf(item.*), item),
2171 .@"enum" => {2186 .@"enum" => {
2172 item.* = @enumFromInt(@byteSwap(@intFromEnum(item.*)));2187 item.* = @enumFromInt(@byteSwap(@intFromEnum(item.*)));
2173 },2188 },
...@@ -2193,6 +2208,7 @@ test byteSwapAllFields {...@@ -2193,6 +2208,7 @@ test byteSwapAllFields {
2193 f3: [1]u8,2208 f3: [1]u8,
2194 f4: bool,2209 f4: bool,
2195 f5: f32,2210 f5: f32,
2211 f6: extern union { f0: u16, f1: u16 },
2196 };2212 };
2197 const K = extern struct {2213 const K = extern struct {
2198 f0: u8,2214 f0: u8,
...@@ -2209,6 +2225,7 @@ test byteSwapAllFields {...@@ -2209,6 +2225,7 @@ test byteSwapAllFields {
2209 .f3 = .{0x12},2225 .f3 = .{0x12},
2210 .f4 = true,2226 .f4 = true,
2211 .f5 = @as(f32, @bitCast(@as(u32, 0x4640e400))),2227 .f5 = @as(f32, @bitCast(@as(u32, 0x4640e400))),
2228 .f6 = .{ .f0 = 0x1234 },
2212 };2229 };
2213 var k = K{2230 var k = K{
2214 .f0 = 0x12,2231 .f0 = 0x12,
...@@ -2227,6 +2244,7 @@ test byteSwapAllFields {...@@ -2227,6 +2244,7 @@ test byteSwapAllFields {
2227 .f3 = .{0x12},2244 .f3 = .{0x12},
2228 .f4 = true,2245 .f4 = true,
2229 .f5 = @as(f32, @bitCast(@as(u32, 0x00e44046))),2246 .f5 = @as(f32, @bitCast(@as(u32, 0x00e44046))),
2247 .f6 = .{ .f0 = 0x3412 },
2230 }, s);2248 }, s);
2231 try std.testing.expectEqual(K{2249 try std.testing.expectEqual(K{
2232 .f0 = 0x12,2250 .f0 = 0x12,
lib/std/testing.zig+12-1
...@@ -153,7 +153,18 @@ fn expectEqualInner(comptime T: type, expected: T, actual: T) !void {...@@ -153,7 +153,18 @@ fn expectEqualInner(comptime T: type, expected: T, actual: T) !void {
153153
154 .@"union" => |union_info| {154 .@"union" => |union_info| {
155 if (union_info.tag_type == null) {155 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 );
157 }168 }
158169
159 const Tag = std.meta.Tag(@TypeOf(expected));170 const Tag = std.meta.Tag(@TypeOf(expected));