I currently try to implement an fs for which I require positional reads/writes.
For testing purposes I would like to have the implementation only take *std.Io.Reader and *std.Io.Writer instead of an *std.Io.File, but I noticed that the interfaces don’t expose positional reads/writes, not even seeking.
Is this something which just isn’t implemented yet or is the intention to use a *std.Io.File directly?
Readers and Writers exist to abstract over streams of bytes. As many of those have no concept of positional reading and writing it likely wouldn’t make sense to add those operations. You can’t write to the 7th byte of a TCP socket, for example. I’d imagine that you should just use File if you need those features
Yeah, for this kind of testing you need a VFS, not a streaming reader/writer. Could
use the Marionette project as an alternative for testing, but it’s probably huge overkill.
1 Like
Yes, but quite a few have that concept: std.Io.File, std.Io.{Writer,Reader}.fixed if we just go with the stdlib, more in other contexts
But it makes testing kind hard.
To add to the above:
- Io.Reader is a buffer, and a function which fills that buffer when more bytes are needed.
- Io.Writer is a buffer, and a few functions to send those bytes on when the buffer is full or flushed.
The methods on each are various convenient ways to work with those buffers. In this context, seeking doesn’t really make sense because the buffer is a limited view into a larger window. Generally, any operations beyond those above live on the implementation’s writer. Eg, std.Io.File.Writer.seekTo, which will flush the writer (because the bytes in the buffer are supposed to go to the old spot), then update the writing location. The related std.Io.File.Reader.seekTo tosses away the currently buffered data, and additional reads will fill the buffer from the new location.
The way i would do this, if you did need implementation agnostic seeking, would be a wrapper interface:
pub const SeekableWriter = struct {
writer: *Io.Writer,
vtable: *const Vtable,
pub const Vtable = struct {
seekTo: *const fn(*Io.Writer, u64) Error!void,
seekBy: *const fn(*Io.Writer, i64) Error!void,
};
pub const Error = ...;
};
For reasons @ScottRedig explained, you need to take care to manage the reader/writers buffer.