diff --git a/lib/std/Io/Reader.zig b/lib/std/Io/Reader.zig index 167e1cb91f..56a70f0781 100644 --- a/lib/std/Io/Reader.zig +++ b/lib/std/Io/Reader.zig @@ -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;