mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 06:13:07 +00:00
Reader.defaultDiscard: Fix for use with an indirect reader
If a Reader implementation implements `stream` by ignoring the Writer, writing directly to its internal buffer, and returning 0, then `defaultDiscard` would not update `seek` and also return 0, which is incorrect and can cause `discardShort` to violate the contract of `VTable.discard` by calling into `vtable.discard` with a non-empty buffer. This commit fixes the problem by advancing seek up to the limit after the stream call. This logic could likely be somewhat simplified in the future depending on how #25170 is resolved.
This commit is contained in:
parent
2ea55d7153
commit
21f9f378f1
@ -200,11 +200,17 @@ pub fn defaultDiscard(r: *Reader, limit: Limit) Error!usize {
|
||||
r.seek = 0;
|
||||
r.end = 0;
|
||||
var d: Writer.Discarding = .init(r.buffer);
|
||||
const n = r.stream(&d.writer, limit) catch |err| switch (err) {
|
||||
var n = r.stream(&d.writer, limit) catch |err| switch (err) {
|
||||
error.WriteFailed => unreachable,
|
||||
error.ReadFailed => return error.ReadFailed,
|
||||
error.EndOfStream => return error.EndOfStream,
|
||||
};
|
||||
// If `stream` wrote to `r.buffer` without going through the writer,
|
||||
// we need to discard as much of the buffered data as possible.
|
||||
const remaining = @intFromEnum(limit) - n;
|
||||
const buffered_n_to_discard = @min(remaining, r.end - r.seek);
|
||||
n += buffered_n_to_discard;
|
||||
r.seek += buffered_n_to_discard;
|
||||
assert(n <= @intFromEnum(limit));
|
||||
return n;
|
||||
}
|
||||
@ -1720,6 +1726,18 @@ fn failingDiscard(r: *Reader, limit: Limit) Error!usize {
|
||||
return error.ReadFailed;
|
||||
}
|
||||
|
||||
test "discardAll that has to call discard multiple times on an indirect reader" {
|
||||
var fr: Reader = .fixed("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
|
||||
var indirect_buffer: [3]u8 = undefined;
|
||||
var tri: std.testing.ReaderIndirect = .init(&fr, &indirect_buffer);
|
||||
const r = &tri.interface;
|
||||
|
||||
try r.discardAll(10);
|
||||
var remaining_buf: [16]u8 = undefined;
|
||||
try r.readSliceAll(&remaining_buf);
|
||||
try std.testing.expectEqualStrings(fr.buffer[10..], remaining_buf[0..]);
|
||||
}
|
||||
|
||||
test "readAlloc when the backing reader provides one byte at a time" {
|
||||
const str = "This is a test";
|
||||
var tiny_buffer: [1]u8 = undefined;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user