Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 67 additions & 37 deletions lib/std/Io/Reader.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1094,33 +1094,41 @@ pub inline fn takeInt(r: *Reader, comptime T: type, endian: std.builtin.Endian)
return std.mem.readInt(T, try r.takeArray(n), endian);
}

/// Asserts the buffer was initialized with a capacity at least `@bitSizeOf(T) / 8`.
pub inline fn peekInt(r: *Reader, comptime T: type, endian: std.builtin.Endian) Error!T {
const n = @divExact(@typeInfo(T).int.bits, 8);
return std.mem.readInt(T, try r.peekArray(n), endian);
}

/// Asserts the buffer was initialized with a capacity at least `n`.
pub fn takeVarInt(r: *Reader, comptime Int: type, endian: std.builtin.Endian, n: usize) Error!Int {
assert(n <= @sizeOf(Int));
return std.mem.readVarInt(Int, try r.take(n), endian);
}

/// Asserts the buffer was initialized with a capacity at least `@sizeOf(T)`.
/// Obtains an unaligned pointer to the beginning of the stream, reinterpreted
/// as a pointer to the provided type, advancing the seek position.
///
/// Advances the seek position.
/// Asserts the buffer was initialized with a capacity at least `@sizeOf(T)`.
///
/// See also:
/// * `peekStruct`
/// * `takeStructEndian`
pub fn takeStruct(r: *Reader, comptime T: type) Error!*align(1) T {
/// * `peekStructReference`
/// * `takeStruct`
pub fn takeStructReference(r: *Reader, comptime T: type) Error!*align(1) T {
// Only extern and packed structs have defined in-memory layout.
comptime assert(@typeInfo(T).@"struct".layout != .auto);
return @ptrCast(try r.takeArray(@sizeOf(T)));
}

/// Asserts the buffer was initialized with a capacity at least `@sizeOf(T)`.
/// Obtains an unaligned pointer to the beginning of the stream, reinterpreted
/// as a pointer to the provided type, without advancing the seek position.
///
/// Does not advance the seek position.
/// Asserts the buffer was initialized with a capacity at least `@sizeOf(T)`.
///
/// See also:
/// * `takeStruct`
/// * `peekStructEndian`
pub fn peekStruct(r: *Reader, comptime T: type) Error!*align(1) T {
/// * `takeStructReference`
/// * `peekStruct`
pub fn peekStructReference(r: *Reader, comptime T: type) Error!*align(1) T {
// Only extern and packed structs have defined in-memory layout.
comptime assert(@typeInfo(T).@"struct".layout != .auto);
return @ptrCast(try r.peekArray(@sizeOf(T)));
Expand All @@ -1132,12 +1140,23 @@ pub fn peekStruct(r: *Reader, comptime T: type) Error!*align(1) T {
/// when `endian` is comptime-known and matches the host endianness.
///
/// See also:
/// * `takeStruct`
/// * `peekStructEndian`
pub inline fn takeStructEndian(r: *Reader, comptime T: type, endian: std.builtin.Endian) Error!T {
var res = (try r.takeStruct(T)).*;
if (native_endian != endian) std.mem.byteSwapAllFields(T, &res);
return res;
/// * `takeStructReference`
/// * `peekStruct`
pub inline fn takeStruct(r: *Reader, comptime T: type, endian: std.builtin.Endian) Error!T {
switch (@typeInfo(T)) {
.@"struct" => |info| switch (info.layout) {
.auto => @compileError("ill-defined memory layout"),
.@"extern" => {
var res = (try r.takeStructReference(T)).*;
if (native_endian != endian) std.mem.byteSwapAllFields(T, &res);
return res;
},
.@"packed" => {
return takeInt(r, info.backing_integer.?, endian);
},
},
else => @compileError("not a struct"),
}
}

/// Asserts the buffer was initialized with a capacity at least `@sizeOf(T)`.
Expand All @@ -1146,12 +1165,23 @@ pub inline fn takeStructEndian(r: *Reader, comptime T: type, endian: std.builtin
/// when `endian` is comptime-known and matches the host endianness.
///
/// See also:
/// * `takeStructEndian`
/// * `peekStruct`
pub inline fn peekStructEndian(r: *Reader, comptime T: type, endian: std.builtin.Endian) Error!T {
var res = (try r.peekStruct(T)).*;
if (native_endian != endian) std.mem.byteSwapAllFields(T, &res);
return res;
/// * `takeStruct`
/// * `peekStructReference`
pub inline fn peekStruct(r: *Reader, comptime T: type, endian: std.builtin.Endian) Error!T {
switch (@typeInfo(T)) {
.@"struct" => |info| switch (info.layout) {
.auto => @compileError("ill-defined memory layout"),
.@"extern" => {
var res = (try r.peekStructReference(T)).*;
if (native_endian != endian) std.mem.byteSwapAllFields(T, &res);
return res;
},
.@"packed" => {
return peekInt(r, info.backing_integer.?, endian);
},
},
else => @compileError("not a struct"),
}
}

pub const TakeEnumError = Error || error{InvalidEnumTag};
Expand Down Expand Up @@ -1517,43 +1547,43 @@ test takeVarInt {
try testing.expectError(error.EndOfStream, r.takeVarInt(u16, .little, 1));
}

test takeStruct {
test takeStructReference {
var r: Reader = .fixed(&.{ 0x12, 0x00, 0x34, 0x56 });
const S = extern struct { a: u8, b: u16 };
switch (native_endian) {
.little => try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x5634 }), (try r.takeStruct(S)).*),
.big => try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x3456 }), (try r.takeStruct(S)).*),
.little => try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x5634 }), (try r.takeStructReference(S)).*),
.big => try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x3456 }), (try r.takeStructReference(S)).*),
}
try testing.expectError(error.EndOfStream, r.takeStruct(S));
try testing.expectError(error.EndOfStream, r.takeStructReference(S));
}

test peekStruct {
test peekStructReference {
var r: Reader = .fixed(&.{ 0x12, 0x00, 0x34, 0x56 });
const S = extern struct { a: u8, b: u16 };
switch (native_endian) {
.little => {
try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x5634 }), (try r.peekStruct(S)).*);
try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x5634 }), (try r.peekStruct(S)).*);
try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x5634 }), (try r.peekStructReference(S)).*);
try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x5634 }), (try r.peekStructReference(S)).*);
},
.big => {
try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x3456 }), (try r.peekStruct(S)).*);
try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x3456 }), (try r.peekStruct(S)).*);
try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x3456 }), (try r.peekStructReference(S)).*);
try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x3456 }), (try r.peekStructReference(S)).*);
},
}
}

test takeStructEndian {
test takeStruct {
var r: Reader = .fixed(&.{ 0x12, 0x00, 0x34, 0x56 });
const S = extern struct { a: u8, b: u16 };
try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x3456 }), try r.takeStructEndian(S, .big));
try testing.expectError(error.EndOfStream, r.takeStructEndian(S, .little));
try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x3456 }), try r.takeStruct(S, .big));
try testing.expectError(error.EndOfStream, r.takeStruct(S, .little));
}

test peekStructEndian {
test peekStruct {
var r: Reader = .fixed(&.{ 0x12, 0x00, 0x34, 0x56 });
const S = extern struct { a: u8, b: u16 };
try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x3456 }), try r.peekStructEndian(S, .big));
try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x5634 }), try r.peekStructEndian(S, .little));
try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x3456 }), try r.peekStruct(S, .big));
try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x5634 }), try r.peekStruct(S, .little));
}

test takeEnum {
Expand Down
9 changes: 1 addition & 8 deletions lib/std/Io/Writer.zig
Original file line number Diff line number Diff line change
Expand Up @@ -796,16 +796,9 @@ pub inline fn writeInt(w: *Writer, comptime T: type, value: T, endian: std.built
return w.writeAll(&bytes);
}

pub fn writeStruct(w: *Writer, value: anytype) Error!void {
// Only extern and packed structs have defined in-memory layout.
comptime assert(@typeInfo(@TypeOf(value)).@"struct".layout != .auto);
return w.writeAll(std.mem.asBytes(&value));
}

/// The function is inline to avoid the dead code in case `endian` is
/// comptime-known and matches host endianness.
/// TODO: make sure this value is not a reference type
pub inline fn writeStructEndian(w: *Writer, value: anytype, endian: std.builtin.Endian) Error!void {
pub inline fn writeStruct(w: *Writer, value: anytype, endian: std.builtin.Endian) Error!void {
switch (@typeInfo(@TypeOf(value))) {
.@"struct" => |info| switch (info.layout) {
.auto => @compileError("ill-defined memory layout"),
Expand Down
5 changes: 5 additions & 0 deletions lib/std/posix/test.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1001,6 +1001,11 @@ test "sigset_t bits" {
if (native_os == .wasi or native_os == .windows)
return error.SkipZigTest;

if (true) {
// https://github.com/ziglang/zig/issues/24380
return error.SkipZigTest;
}

const S = struct {
var expected_sig: i32 = undefined;
var handler_called_count: u32 = 0;
Expand Down
2 changes: 1 addition & 1 deletion src/Zcu.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2809,7 +2809,7 @@ pub fn loadZirCache(gpa: Allocator, cache_file: std.fs.File) !Zir {
var buffer: [2000]u8 = undefined;
var file_reader = cache_file.reader(&buffer);
return result: {
const header = file_reader.interface.takeStruct(Zir.Header) catch |err| break :result err;
const header = file_reader.interface.takeStructReference(Zir.Header) catch |err| break :result err;
break :result loadZirCacheBody(gpa, header.*, &file_reader.interface);
} catch |err| switch (err) {
error.ReadFailed => return file_reader.err.?,
Expand Down
2 changes: 1 addition & 1 deletion src/Zcu/PerThread.zig
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@ fn loadZirZoirCache(
const cache_br = &cache_fr.interface;

// First we read the header to determine the lengths of arrays.
const header = (cache_br.takeStruct(Header) catch |err| switch (err) {
const header = (cache_br.takeStructReference(Header) catch |err| switch (err) {
error.ReadFailed => return cache_fr.err.?,
// This can happen if Zig bails out of this function between creating
// the cached file and writing it.
Expand Down