mirror of
https://github.com/ziglang/zig.git
synced 2024-11-24 21:30:14 +00:00
support packed structs in std.io.Reader and std.io.Writer
This commit is contained in:
parent
0367f18cb9
commit
ed612f40af
@ -324,20 +324,47 @@ pub fn isBytes(self: Self, slice: []const u8) anyerror!bool {
|
||||
return matches;
|
||||
}
|
||||
|
||||
/// Read a struct from the stream.
|
||||
/// Only packed and extern structs are supported.
|
||||
/// Packed structs must have a `@bitSizeOf` that is a multiple of eight.
|
||||
pub fn readStruct(self: Self, comptime T: type) anyerror!T {
|
||||
// Only extern and packed structs have defined in-memory layout.
|
||||
comptime assert(@typeInfo(T).@"struct".layout != .auto);
|
||||
var res: [1]T = undefined;
|
||||
try self.readNoEof(mem.sliceAsBytes(res[0..]));
|
||||
return res[0];
|
||||
switch (@typeInfo(T).@"struct".layout) {
|
||||
.auto => @compileError("readStruct only supports packed and extern structs."),
|
||||
.@"extern" => {
|
||||
var res: [1]T = undefined;
|
||||
try self.readNoEof(mem.sliceAsBytes(res[0..]));
|
||||
return res[0];
|
||||
},
|
||||
.@"packed" => {
|
||||
var bytes: [@divExact(@bitSizeOf(T), 8)]u8 = undefined;
|
||||
try self.readNoEof(&bytes);
|
||||
return @bitCast(bytes);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Read a struct having the specified endianness into the host endianness representation.
|
||||
/// Only packed and extern structs are supported.
|
||||
/// Packed structs must have a `@bitSizeOf` that is a multiple of eight.
|
||||
pub fn readStructEndian(self: Self, comptime T: type, endian: std.builtin.Endian) anyerror!T {
|
||||
var res = try self.readStruct(T);
|
||||
if (native_endian != endian) {
|
||||
mem.byteSwapAllFields(T, &res);
|
||||
switch (@typeInfo(T).@"struct".layout) {
|
||||
.auto => @compileError("readStructEndian only supports packed and extern structs."),
|
||||
.@"extern" => {
|
||||
var res = try self.readStruct(T);
|
||||
if (native_endian != endian) {
|
||||
mem.byteSwapAllFields(T, &res);
|
||||
}
|
||||
return res;
|
||||
},
|
||||
.@"packed" => {
|
||||
var bytes: [@divExact(@bitSizeOf(T), 8)]u8 = undefined;
|
||||
try self.readNoEof(&bytes);
|
||||
if (native_endian != endian) {
|
||||
mem.reverse(u8, &bytes);
|
||||
}
|
||||
return @bitCast(bytes);
|
||||
},
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/// Reads an integer with the same size as the given enum's tag type. If the integer matches
|
||||
|
@ -1,6 +1,7 @@
|
||||
const builtin = @import("builtin");
|
||||
const std = @import("../../std.zig");
|
||||
const testing = std.testing;
|
||||
const native_endian = @import("builtin").target.cpu.arch.endian();
|
||||
|
||||
test "Reader" {
|
||||
var buf = "a\x02".*;
|
||||
@ -370,3 +371,44 @@ test "readIntoBoundedBytes correctly reads into a provided bounded array" {
|
||||
try reader.readIntoBoundedBytes(10000, &bounded_array);
|
||||
try testing.expectEqualStrings(bounded_array.slice(), test_string);
|
||||
}
|
||||
|
||||
test "readStructEndian reads packed structs without padding and in correct field order" {
|
||||
const buf = [3]u8{ 11, 12, 13 };
|
||||
var fis = std.io.fixedBufferStream(&buf);
|
||||
const reader = fis.reader();
|
||||
|
||||
const PackedStruct = packed struct(u24) { a: u8, b: u8, c: u8 };
|
||||
|
||||
try testing.expectEqualDeep(
|
||||
PackedStruct{ .a = 11, .b = 12, .c = 13 },
|
||||
reader.readStructEndian(PackedStruct, .little),
|
||||
);
|
||||
fis.reset();
|
||||
try testing.expectEqualDeep(
|
||||
PackedStruct{ .a = 13, .b = 12, .c = 11 },
|
||||
reader.readStructEndian(PackedStruct, .big),
|
||||
);
|
||||
}
|
||||
|
||||
test "readStruct reads packed structs without padding and in correct field order" {
|
||||
const buf = [3]u8{ 11, 12, 13 };
|
||||
var fis = std.io.fixedBufferStream(&buf);
|
||||
const reader = fis.reader();
|
||||
|
||||
const PackedStruct = packed struct(u24) { a: u8, b: u8, c: u8 };
|
||||
|
||||
switch (native_endian) {
|
||||
.little => {
|
||||
try testing.expectEqualDeep(
|
||||
PackedStruct{ .a = 11, .b = 12, .c = 13 },
|
||||
reader.readStruct(PackedStruct),
|
||||
);
|
||||
},
|
||||
.big => {
|
||||
try testing.expectEqualDeep(
|
||||
PackedStruct{ .a = 13, .b = 12, .c = 11 },
|
||||
reader.readStruct(PackedStruct),
|
||||
);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -54,20 +54,46 @@ pub inline fn writeInt(self: Self, comptime T: type, value: T, endian: std.built
|
||||
return self.writeAll(&bytes);
|
||||
}
|
||||
|
||||
/// Write a struct to the stream.
|
||||
/// Only packed and extern structs are supported.
|
||||
/// Packed structs must have a `@bitSizeOf` that is a multiple of eight.
|
||||
pub fn writeStruct(self: Self, value: anytype) anyerror!void {
|
||||
// Only extern and packed structs have defined in-memory layout.
|
||||
comptime assert(@typeInfo(@TypeOf(value)).@"struct".layout != .auto);
|
||||
return self.writeAll(mem.asBytes(&value));
|
||||
switch (@typeInfo(@TypeOf(value)).@"struct".layout) {
|
||||
.auto => @compileError("writeStruct only supports packed and extern structs."),
|
||||
.@"extern" => {
|
||||
return try self.writeAll(mem.asBytes(&value));
|
||||
},
|
||||
.@"packed" => {
|
||||
const bytes: [@divExact(@bitSizeOf(@TypeOf(value)), 8)]u8 = @bitCast(value);
|
||||
try self.writeAll(&bytes);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Write a struct to the stream in the specified endianness.
|
||||
/// Only packed and extern structs are supported.
|
||||
/// Packed structs must have a `@bitSizeOf` that is a multiple of eight.
|
||||
pub fn writeStructEndian(self: Self, value: anytype, endian: std.builtin.Endian) anyerror!void {
|
||||
// TODO: make sure this value is not a reference type
|
||||
if (native_endian == endian) {
|
||||
return self.writeStruct(value);
|
||||
} else {
|
||||
var copy = value;
|
||||
mem.byteSwapAllFields(@TypeOf(value), ©);
|
||||
return self.writeStruct(copy);
|
||||
switch (@typeInfo(@TypeOf(value)).@"struct".layout) {
|
||||
.auto => @compileError("writeStructEndian only supports packed and extern structs."),
|
||||
.@"extern" => {
|
||||
if (native_endian == endian) {
|
||||
return try self.writeStruct(value);
|
||||
} else {
|
||||
var copy = value;
|
||||
mem.byteSwapAllFields(@TypeOf(value), ©);
|
||||
return try self.writeStruct(copy);
|
||||
}
|
||||
},
|
||||
.@"packed" => {
|
||||
var bytes: [@divExact(@bitSizeOf(@TypeOf(value)), 8)]u8 = @bitCast(value);
|
||||
if (native_endian != endian) {
|
||||
mem.reverse(u8, &bytes);
|
||||
}
|
||||
return try self.writeAll(&bytes);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@ -81,3 +107,7 @@ pub fn writeFile(self: Self, file: std.fs.File) anyerror!void {
|
||||
if (n < buf.len) return;
|
||||
}
|
||||
}
|
||||
|
||||
test {
|
||||
_ = @import("Writer/test.zig");
|
||||
}
|
||||
|
35
lib/std/io/Writer/test.zig
Normal file
35
lib/std/io/Writer/test.zig
Normal file
@ -0,0 +1,35 @@
|
||||
const std = @import("../../std.zig");
|
||||
const testing = std.testing;
|
||||
const native_endian = @import("builtin").target.cpu.arch.endian();
|
||||
|
||||
test "writeStruct writes packed structs without padding" {
|
||||
var buf: [3]u8 = undefined;
|
||||
var fis = std.io.fixedBufferStream(&buf);
|
||||
const writer = fis.writer();
|
||||
|
||||
const PackedStruct = packed struct(u24) { a: u8, b: u8, c: u8 };
|
||||
|
||||
try writer.writeStruct(PackedStruct{ .a = 11, .b = 12, .c = 13 });
|
||||
switch (native_endian) {
|
||||
.little => {
|
||||
try testing.expectEqualSlices(u8, &.{ 11, 12, 13 }, &buf);
|
||||
},
|
||||
.big => {
|
||||
try testing.expectEqualSlices(u8, &.{ 13, 12, 11 }, &buf);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
test "writeStructEndian writes packed structs without padding and in correct field order" {
|
||||
var buf: [3]u8 = undefined;
|
||||
var fis = std.io.fixedBufferStream(&buf);
|
||||
const writer = fis.writer();
|
||||
|
||||
const PackedStruct = packed struct(u24) { a: u8, b: u8, c: u8 };
|
||||
|
||||
try writer.writeStructEndian(PackedStruct{ .a = 11, .b = 12, .c = 13 }, .little);
|
||||
try testing.expectEqualSlices(u8, &.{ 11, 12, 13 }, &buf);
|
||||
fis.reset();
|
||||
try writer.writeStructEndian(PackedStruct{ .a = 11, .b = 12, .c = 13 }, .big);
|
||||
try testing.expectEqualSlices(u8, &.{ 13, 12, 11 }, &buf);
|
||||
}
|
Loading…
Reference in New Issue
Block a user