Skip to content

Commit dbe0e0c

Browse files
authored
Merge pull request #24464 from ziglang/fixes
std.Io fixes, docs, and tests
2 parents 94e0c85 + 6d39c29 commit dbe0e0c

File tree

2 files changed

+59
-4
lines changed

2 files changed

+59
-4
lines changed

lib/std/Io/Reader.zig

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1303,6 +1303,13 @@ fn takeMultipleOf7Leb128(r: *Reader, comptime Result: type) TakeLeb128Error!Resu
13031303
}
13041304

13051305
/// Left-aligns data such that `r.seek` becomes zero.
1306+
///
1307+
/// If `r.seek` is not already zero then `buffer` is mutated, making it illegal
1308+
/// to call this function with a const-casted `buffer`, such as in the case of
1309+
/// `fixed`. This issue can be avoided:
1310+
/// * in implementations, by attempting a read before a rebase, in which
1311+
/// case the read will return `error.EndOfStream`, preventing the rebase.
1312+
/// * in usage, by copying into a mutable buffer before initializing `fixed`.
13061313
pub fn rebase(r: *Reader) void {
13071314
if (r.seek == 0) return;
13081315
const data = r.buffer[r.seek..r.end];
@@ -1315,6 +1322,13 @@ pub fn rebase(r: *Reader) void {
13151322
/// if necessary.
13161323
///
13171324
/// Asserts `capacity` is within the buffer capacity.
1325+
///
1326+
/// If the rebase occurs then `buffer` is mutated, making it illegal to call
1327+
/// this function with a const-casted `buffer`, such as in the case of `fixed`.
1328+
/// This issue can be avoided:
1329+
/// * in implementations, by attempting a read before a rebase, in which
1330+
/// case the read will return `error.EndOfStream`, preventing the rebase.
1331+
/// * in usage, by copying into a mutable buffer before initializing `fixed`.
13181332
pub fn rebaseCapacity(r: *Reader, capacity: usize) void {
13191333
if (r.end > r.buffer.len - capacity) rebase(r);
13201334
}

lib/std/Io/Writer.zig

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2194,8 +2194,10 @@ pub const Discarding = struct {
21942194
const d: *Discarding = @alignCast(@fieldParentPtr("writer", w));
21952195
d.count += w.end;
21962196
w.end = 0;
2197+
if (limit == .nothing) return 0;
21972198
if (file_reader.getSize()) |size| {
21982199
const n = limit.minInt64(size - file_reader.pos);
2200+
if (n == 0) return error.EndOfStream;
21992201
file_reader.seekBy(@intCast(n)) catch return error.Unimplemented;
22002202
w.end = 0;
22012203
d.count += n;
@@ -2489,18 +2491,17 @@ pub const Allocating = struct {
24892491

24902492
fn sendFile(w: *Writer, file_reader: *File.Reader, limit: std.io.Limit) FileError!usize {
24912493
if (File.Handle == void) return error.Unimplemented;
2494+
if (limit == .nothing) return 0;
24922495
const a: *Allocating = @fieldParentPtr("writer", w);
24932496
const gpa = a.allocator;
24942497
var list = a.toArrayList();
24952498
defer setArrayList(a, list);
24962499
const pos = file_reader.pos;
24972500
const additional = if (file_reader.getSize()) |size| size - pos else |_| std.atomic.cache_line;
2501+
if (additional == 0) return error.EndOfStream;
24982502
list.ensureUnusedCapacity(gpa, limit.minInt64(additional)) catch return error.WriteFailed;
24992503
const dest = limit.slice(list.unusedCapacitySlice());
2500-
const n = file_reader.read(dest) catch |err| switch (err) {
2501-
error.ReadFailed => return error.ReadFailed,
2502-
error.EndOfStream => 0,
2503-
};
2504+
const n = try file_reader.read(dest);
25042505
list.items.len += n;
25052506
return n;
25062507
}
@@ -2522,3 +2523,43 @@ pub const Allocating = struct {
25222523
try testing.expectEqualSlices(u8, "x: 42\ny: 1234\n", a.getWritten());
25232524
}
25242525
};
2526+
2527+
test "discarding sendFile" {
2528+
var tmp_dir = testing.tmpDir(.{});
2529+
defer tmp_dir.cleanup();
2530+
2531+
const file = try tmp_dir.dir.createFile("input.txt", .{ .read = true });
2532+
defer file.close();
2533+
var r_buffer: [256]u8 = undefined;
2534+
var file_writer: std.fs.File.Writer = .init(file, &r_buffer);
2535+
try file_writer.interface.writeByte('h');
2536+
try file_writer.interface.flush();
2537+
2538+
var file_reader = file_writer.moveToReader();
2539+
try file_reader.seekTo(0);
2540+
2541+
var w_buffer: [256]u8 = undefined;
2542+
var discarding: std.io.Writer.Discarding = .init(&w_buffer);
2543+
2544+
_ = try file_reader.interface.streamRemaining(&discarding.writer);
2545+
}
2546+
2547+
test "allocating sendFile" {
2548+
var tmp_dir = testing.tmpDir(.{});
2549+
defer tmp_dir.cleanup();
2550+
2551+
const file = try tmp_dir.dir.createFile("input.txt", .{ .read = true });
2552+
defer file.close();
2553+
var r_buffer: [256]u8 = undefined;
2554+
var file_writer: std.fs.File.Writer = .init(file, &r_buffer);
2555+
try file_writer.interface.writeByte('h');
2556+
try file_writer.interface.flush();
2557+
2558+
var file_reader = file_writer.moveToReader();
2559+
try file_reader.seekTo(0);
2560+
2561+
var allocating: std.io.Writer.Allocating = .init(std.testing.allocator);
2562+
defer allocating.deinit();
2563+
2564+
_ = try file_reader.interface.streamRemaining(&allocating.writer);
2565+
}

0 commit comments

Comments
 (0)