A Io.Reader that gets its data from another Io.Reader, and always
writes to its own buffer (and returns 0) during stream and readVec.
pub const ReaderIndirect = struct
pub const ReaderIndirect = struct {
in: *Io.Reader,
interface: Io.Reader,
pub fn init(in: *Io.Reader, buffer: []u8) ReaderIndirect {
return .{
.in = in,
.interface = .{
.vtable = &.{
.stream = stream,
.readVec = readVec,
},
.buffer = buffer,
.seek = 0,
.end = 0,
},
};
}
fn readVec(r: *Io.Reader, _: [][]u8) Io.Reader.Error!usize {
try streamInner(r);
return 0;
}
fn stream(r: *Io.Reader, _: *Io.Writer, _: Io.Limit) Io.Reader.StreamError!usize {
try streamInner(r);
return 0;
}
fn streamInner(r: *Io.Reader) Io.Reader.Error!void {
const r_indirect: *ReaderIndirect = @alignCast(@fieldParentPtr("interface", r));
// If there's no room remaining in the buffer at all, make room.
if (r.buffer.len == r.end) {
try r.rebase(r.buffer.len);
}
var writer: Io.Writer = .{
.buffer = r.buffer,
.end = r.end,
.vtable = &.{
.drain = Io.Writer.unreachableDrain,
.rebase = Io.Writer.unreachableRebase,
},
};
defer r.end = writer.end;
r_indirect.in.streamExact(&writer, r.buffer.len - r.end) catch |err| switch (err) {
// Only forward EndOfStream if no new bytes were written to the buffer
error.EndOfStream => |e| if (r.end == writer.end) {
return e;
},
error.WriteFailed => unreachable,
else => |e| return e,
};
}
}