aboutsummaryrefslogtreecommitdiff
path: root/lib/std/testing.zig
diff options
context:
space:
mode:
Diffstat (limited to 'lib/std/testing.zig')
-rw-r--r--lib/std/testing.zig60
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,
+ };
+ }
+};