I am misunderstanding buffers and IO

Hello,

I think I am misunderstanding the way buffering works and I would really appreciate some help clearing it up.

I have the following file, which contains the letters of the alphabet:

$ cat file
ABCDEFGHIJKLMNOPQRSTUVWXYZ

I expected the following program to run fine. It doesn’t. It will only work if I increase the size of the buffer. This is a simplified example, in my actual code I’d end up needing a buffer the size of the file even though I’m only ever reading a few bytes at a time.

const std = @import("std");

pub fn main(init: std.process.Init) !void {
    var buffer = std.mem.zeroes([4]u8);
    const workdir = std.Io.Dir.cwd();

    const alphabet_file = try workdir.openFile(init.io, "file", .{ .mode = .read_only });
    defer alphabet_file.close(init.io);

    var reader = alphabet_file.reader(init.io, &buffer);

    std.debug.print("{x}\n", .{try reader.interface.takeByte()});  // 41
    reader.interface.toss(2);  // skip 42 and 43
    std.debug.print("{x}\n", .{try reader.interface.takeByte()});  // 44
    reader.interface.toss(2);  // thread 8760 panic: reached unreachable code (expected to skip 45 and 46)
    std.debug.print("{x}\n", .{try reader.interface.takeByte()});  // (expected 47)
}

I am either misunderstanding how buffering is supposed to work (I thought this would be fine as I am never trying to read, or even toss, more bytes at a time than the size of the buffer), or my understanding is correct by my code is wrong.

I have already read the post on IO in 0.16 here and I don’t see anything that contradicts what I’m trying to do.

Thank you.

toss only removes data from the buffer ant it asserts the buffer was not empty.

takeByte will only fill the buffer if there is no data.

What happens is:
takeByte, the buffer is empty so it is filled, it probably is full now since it is small
toss 2 from buffer, which now only has 1 byte,
takeByte, the buffer has a byte so it takes it, it is now empty,
toss 2, the buffer is empty, it trips the assert.


instead of toss, use discard or discardShort, that will consume from both the buffer, and the underlying source if the buffer is empty.

5 Likes

Thank you for the explanation and the redirection to the right functions! It turns out discardAll does pretty much what I thought toss was doing.