diff --git a/lib/std/io.zig b/lib/std/io.zig index 22ba0b9bf4f8..553b4c208ccc 100644 --- a/lib/std/io.zig +++ b/lib/std/io.zig @@ -109,30 +109,63 @@ pub fn readFileAlloc(allocator: *mem.Allocator, path: []const u8) ![]u8 { } pub fn BufferedInStream(comptime Error: type) type { - return BufferedInStreamCustom(mem.page_size, Error); + return BufferedInStreamCustom(.{ .Static = mem.page_size }, Error); } -pub fn BufferedInStreamCustom(comptime buffer_size: usize, comptime Error: type) type { +/// Creates a readable stream which buffers data +/// It also supports 'un-reading' data, so that it can be read again. +/// This makes look-ahead style parsing much easier. +pub fn BufferedInStreamCustom(comptime buffer_type: std.fifo.LinearFifoBufferType, comptime InStreamError: type) type { return struct { const Self = @This(); - const Stream = InStream(Error); + pub const Error = InStreamError; + pub const Stream = InStream(Error); stream: Stream, + base: *Stream, - unbuffered_in_stream: *Stream, - - const FifoType = std.fifo.LinearFifo(u8, std.fifo.LinearFifoBufferType{ .Static = buffer_size }); + const FifoType = std.fifo.LinearFifo(u8, buffer_type); fifo: FifoType, - pub fn init(unbuffered_in_stream: *Stream) Self { - return Self{ - .unbuffered_in_stream = unbuffered_in_stream, - .fifo = FifoType.init(), - .stream = Stream{ .readFn = readFn }, - }; + pub usingnamespace switch (buffer_type) { + .Static => struct { + pub fn init(base: *Stream) Self { + return .{ + .base = base, + .fifo = FifoType.init(), + .stream = Stream{ .readFn = readFn }, + }; + } + }, + .Slice => struct { + pub fn init(base: *Stream, buf: []u8) Self { + return .{ + .base = base, + .fifo = FifoType.init(buf), + .stream = Stream{ .readFn = readFn }, + }; + } + }, + .Dynamic => struct { + pub fn init(base: *Stream, allocator: *mem.Allocator) Self { + return .{ + .base = base, + .fifo = FifoType.init(allocator), + .stream = Stream{ .readFn = readFn }, + }; + } + }, + }; + + pub fn putBackByte(self: *Self, byte: u8) !void { + try self.putBack(&[_]u8{byte}); + } + + pub fn putBack(self: *Self, bytes: []const u8) !void { + try self.fifo.unget(bytes); } - fn readFn(in_stream: *Stream, dest: []u8) !usize { + fn readFn(in_stream: *Stream, dest: []u8) Error!usize { const self = @fieldParentPtr(Self, "stream", in_stream); var dest_index: usize = 0; while (dest_index < dest.len) { @@ -141,7 +174,7 @@ pub fn BufferedInStreamCustom(comptime buffer_size: usize, comptime Error: type) // fifo empty, fill it const writable = self.fifo.writableSlice(0); assert(writable.len > 0); - const n = try self.unbuffered_in_stream.read(writable); + const n = try self.base.read(writable); if (n == 0) { // reading from the unbuffered stream returned nothing // so we have nothing left to read. @@ -194,72 +227,6 @@ test "io.BufferedInStream" { testing.expectEqualSlices(u8, str, res); } -/// Creates a stream which supports 'un-reading' data, so that it can be read again. -/// This makes look-ahead style parsing much easier. -pub fn PeekStream(comptime buffer_type: std.fifo.LinearFifoBufferType, comptime InStreamError: type) type { - return struct { - const Self = @This(); - pub const Error = InStreamError; - pub const Stream = InStream(Error); - - stream: Stream, - base: *Stream, - - const FifoType = std.fifo.LinearFifo(u8, buffer_type); - fifo: FifoType, - - pub usingnamespace switch (buffer_type) { - .Static => struct { - pub fn init(base: *Stream) Self { - return .{ - .base = base, - .fifo = FifoType.init(), - .stream = Stream{ .readFn = readFn }, - }; - } - }, - .Slice => struct { - pub fn init(base: *Stream, buf: []u8) Self { - return .{ - .base = base, - .fifo = FifoType.init(buf), - .stream = Stream{ .readFn = readFn }, - }; - } - }, - .Dynamic => struct { - pub fn init(base: *Stream, allocator: *mem.Allocator) Self { - return .{ - .base = base, - .fifo = FifoType.init(allocator), - .stream = Stream{ .readFn = readFn }, - }; - } - }, - }; - - pub fn putBackByte(self: *Self, byte: u8) !void { - try self.putBack(&[_]u8{byte}); - } - - pub fn putBack(self: *Self, bytes: []const u8) !void { - try self.fifo.unget(bytes); - } - - fn readFn(in_stream: *Stream, dest: []u8) Error!usize { - const self = @fieldParentPtr(Self, "stream", in_stream); - - // copy over anything putBack()'d - var dest_index = self.fifo.read(dest); - if (dest_index == dest.len) return dest_index; - - // ask the backing stream for more - dest_index += try self.base.read(dest[dest_index..]); - return dest_index; - } - }; -} - pub const SliceInStream = struct { const Self = @This(); pub const Error = error{}; diff --git a/lib/std/io/test.zig b/lib/std/io/test.zig index 7716e603a017..0bc0e91e7c87 100644 --- a/lib/std/io/test.zig +++ b/lib/std/io/test.zig @@ -91,10 +91,10 @@ test "SliceInStream" { expect(read == 0); } -test "PeekStream" { +test "BufferedInStream putBack" { const bytes = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8 }; var ss = io.SliceInStream.init(&bytes); - var ps = io.PeekStream(.{ .Static = 2 }, io.SliceInStream.Error).init(&ss.stream); + var ps = io.BufferedInStreamCustom(.{ .Static = 2 }, io.SliceInStream.Error).init(&ss.stream); var dest: [4]u8 = undefined;