I’m having difficulties in understanding how the new API should be used. I didn’t understand much the old one either tbh. Is there somewhere a guide on this subject (valid for 0.15.1)? Or at least some example?
For example I was reading a file like this
var buffered = std.io.bufferedReader(file.reader());
const reader = buffered.reader();
while (try reader.readUntilDelimiterOrEofAlloc(e.allocator, '\n', maxUsize)) |line| {
What would be now the way to read a file line by line with a buffered reader? I’m trying this but it doesn’t work:
/// Read all lines from file.
fn readLines(e: *Editor, file: std.fs.File) !void {
var buf: [1024]u8 = undefined;
const reader = file.reader(&buf);
while (try reader.takeDelimiterExclusive('\n')) |line| {
// stuff
}
}
/// Read all lines from file.
fn readLines(e: *Editor, file: std.fs.File) !void {
var buf: [1024 * 1024]u8 = undefined;
var reader = file.reader(&buf).interface;
while (reader.takeDelimiterExclusive('\n')) |line| {
try e.insertRow(e.buffer.rows.items.len, line);
} else |err| if (err != error.EndOfStream) return err;
}
called like this:
// read lines if the file could be opened
const file = std.fs.cwd().openFile(path, .{ .mode = .read_only });
if (file) |f| {
defer f.close();
try e.readLines(f);
}
but when I try to read a file I get
Summary
thread 41462 panic: switch on corrupt value
/home/gianmaria/.local/versions/zig/0.15.1/lib/std/fs/File.zig:1315:17: 0x1195aab in stream (std.zig)
switch (r.mode) {
^
/home/gianmaria/.local/versions/zig/0.15.1/lib/std/Io/Reader.zig:774:34: 0x117ee76 in peekDelimiterInclusive (std.zig)
const n = r.vtable.stream(r, &writer, .limited(end_cap.len)) catch |err| switch (err) {
^
/home/gianmaria/.local/versions/zig/0.15.1/lib/std/Io/Reader.zig:804:44: 0x116e993 in takeDelimiterExclusive (std.zig)
const result = r.peekDelimiterInclusive(delimiter) catch |err| switch (err) {
^
/home/gianmaria/Progetti/zig/kilo/src/Editor.zig:162:41: 0x1153233 in readLines (main.zig)
while (reader.takeDelimiterExclusive('\n')) |line| {
^
/home/gianmaria/Progetti/zig/kilo/src/Editor.zig:94:24: 0x11540e6 in openFile (main.zig)
try e.readLines(f);
^
/home/gianmaria/Progetti/zig/kilo/src/Editor.zig:64:23: 0x116ae5e in startUp (main.zig)
try e.openFile(name);
^
/home/gianmaria/Progetti/zig/kilo/src/main.zig:25:18: 0x116b61e in main (main.zig)
try e.startUp(args.next()); // possible file to open
^
/home/gianmaria/.local/versions/zig/0.15.1/lib/std/start.zig:627:37: 0x116c0d9 in posixCallMainAndExit (std.zig)
const result = root.main() catch |err| {
^
/home/gianmaria/.local/versions/zig/0.15.1/lib/std/start.zig:232:5: 0x114f811 in _start (std.zig)
asm volatile (switch (native_arch) {
^
???:?:?: 0x0 in ??? (???)
Aborted (core dumped)
If I reduce the buffer size to 1024 I get instead
Summary
error: ReadFailed
/home/gianmaria/Progetti/zig/kilo/src/Editor.zig:164:48: 0x1153443 in readLines (main.zig)
} else |err| if (err != error.EndOfStream) return err;
^
/home/gianmaria/Progetti/zig/kilo/src/Editor.zig:94:9: 0x115415e in openFile (main.zig)
try e.readLines(f);
^
/home/gianmaria/Progetti/zig/kilo/src/Editor.zig:64:9: 0x116ae76 in startUp (main.zig)
try e.openFile(name);
^
/home/gianmaria/Progetti/zig/kilo/src/main.zig:25:5: 0x116b6f3 in main (main.zig)
try e.startUp(args.next()); // possible file to open
^
/// Read all lines from file.
fn readLines(e: *Editor, file: std.fs.File) !void {
var buf: [1024 * 1024]u8 = undefined;
var reader = file.reader(&buf).interface;
while (reader.takeDelimiterExclusive('\n')) |line| {
try e.insertRow(e.buffer.rows.items.len, line);
} else |err| if (err != error.EndOfStream) return err;
}
The problem you were running into was that std.fs.File.Reader needs to remain allocated. You made a copy of the std.Io.Reader interface, and then used that. This causes a problem when the std.fs.File.Reader functions do a @fieldParentPtr to find the address of the std.fs.File.Reader from the *std.Io.Reader address.
Got it. In general it’s really hard to know which intermediates you can use and which you cannot. The error message wasn’t too helpful either. Sometimes you get some const-related errors (understandable) but in this case it was nothing like that.
If you take a pointer to a temporary you end up with a const pointer, I don’t think you want a *const Writer, because most of the methods on it require a *Writer so you can actually use it for writing.
Thanks got it. Maybe hiding dangerous intermediates behind function calls that return underscored members would work in this kind of cases? I just tried replacing in std all usages of interface with _interface, then having methods like:
var reader = file.reader(buf).interface();
while (reader.takeDelimiterExclusive('\n')) |line| {
src/Editor.zig|161 col 34| error: expected type '*fs.File.Reader', found '*const fs.File.Reader'
while this would compile and work
var reader = file.reader(buf);
while (reader.interface().takeDelimiterExclusive('\n')) |line| {
Just saying… it would be the usual const-related error for which we know the cure.
Or just methods like reader.getInterface(), so that to renaming the field isn’t necessary.