Today’s rabbit hole comes from《Advent of Zig 2015年12日》, in which I’m forced to read a file against my will. Thus, I read.
The Reader
test {
const io = std.testing.io;
const file = try std.Io.Dir.cwd().openFile(io, "15-12", .{});
defer file.close(io);
var buff: [64]u8 = undefined;
var reader = file.reader(io, &buff);
const r = &reader.interface;
log("\n{any}\n", .{file.length(io)});
...
}
Pretty standard as far as I understand it. Although, the absolutely necessary & in const r = &reader.interface; was not immediately obvious for a Zig n00b such as myself.
The Reading
test {
...
var n: u32 = 0;
while (true) : (n += 1) {
const slice = r.take(buff.len) catch break;
....
}
}
My first approach was something like this.
But “this” doesn’t read the entire thing. When reaching the end of the file I get a EndOfStream and break through the while loop. This is due to Reader > take() > peek() > fill() > fillUnbuffered() > try r.vtable.readVec > etc the point being that the mayority of this functions state:
If there are fewer than
nbytes left in the stream,error.EndOfStreamis returned instead.
The Journey
My first instinct was to just look for a function that wouldn’t do such thing, in the end, there are lots of them that return some kind of []u8 so it’s just a matter of time until I find one such as the returning slice has a length equal to the remaining characters to be read.
To my surprise, after reading the entirety of the Reader.zig file I couldn’t find a function that does this in a easy-enough way for me to understand.
For example:
streamRemainingrequires a writer for which I can’t justify its creation.allocRemaining(and friends) require an allocator that I don’t need, given my buffer.
At some point I found a cute little function called bufferedLen and I really liked it’s r.end - r.seek pattern. Curiously enough, the same subtraction is done by hand in many places in the code instead of using this function, which I found curious. I was expecting it to be inlined too, or to have a private inlined version. So I came back to my code and did:
test {
...
var n: u32 = 0;
while (true) : (n += 1) {
const slice = r.take(buff.len) catch try r.take(r.end - r.seek);
....
}
}
Problem solved. But.
Questions
What the hell?
This was a lot of work for such a stupid resolution and I’m almost 100% that I’m missing something really obvious. If Andrew responds again with a single builtin function name I’m gonna scream.
Some questions for you!
- How would you write this?
- Is the idea to
peek()and thentake()/toss()after handling errors? - Why isn’t there a function that returns a
?[]u8so I can just plonk it into a while loop?
I you read all this, you are a champ.