diff options
Diffstat (limited to 'lib/std/testing.zig')
| -rw-r--r-- | lib/std/testing.zig | 60 |
1 files changed, 60 insertions, 0 deletions
diff --git a/lib/std/testing.zig b/lib/std/testing.zig index 1c6c639796..e1e78c3bec 100644 --- a/lib/std/testing.zig +++ b/lib/std/testing.zig @@ -1242,3 +1242,63 @@ pub const Reader = struct { return n; } }; + +/// A `std.Io.Reader` that gets its data from another `std.Io.Reader`, and always +/// writes to its own buffer (and returns 0) during `stream` and `readVec`. +pub const ReaderIndirect = struct { + in: *std.Io.Reader, + interface: std.Io.Reader, + + pub fn init(in: *std.Io.Reader, buffer: []u8) ReaderIndirect { + return .{ + .in = in, + .interface = .{ + .vtable = &.{ + .stream = stream, + .readVec = readVec, + }, + .buffer = buffer, + .seek = 0, + .end = 0, + }, + }; + } + + fn readVec(r: *std.Io.Reader, _: [][]u8) std.Io.Reader.Error!usize { + try streamInner(r); + return 0; + } + + fn stream(r: *std.Io.Reader, _: *std.Io.Writer, _: std.Io.Limit) std.Io.Reader.StreamError!usize { + try streamInner(r); + return 0; + } + + fn streamInner(r: *std.Io.Reader) std.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: std.Io.Writer = .{ + .buffer = r.buffer, + .end = r.end, + .vtable = &.{ + .drain = std.Io.Writer.unreachableDrain, + .rebase = std.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, + }; + } +}; |
