1const std = @import("../std.zig"); 2const io = std.io; 3const assert = std.debug.assert; 4const testing = std.testing; 5 6pub fn BufferedReader(comptime buffer_size: usize, comptime ReaderType: type) type { 7 return struct { 8 unbuffered_reader: ReaderType, 9 fifo: FifoType = FifoType.init(), 10 11 pub const Error = ReaderType.Error; 12 pub const Reader = io.Reader(*Self, Error, read); 13 14 const Self = @This(); 15 const FifoType = std.fifo.LinearFifo(u8, std.fifo.LinearFifoBufferType{ .Static = buffer_size }); 16 17 pub fn read(self: *Self, dest: []u8) Error!usize { 18 var dest_index: usize = 0; 19 while (dest_index < dest.len) { 20 const written = self.fifo.read(dest[dest_index..]); 21 if (written == 0) { 22 // fifo empty, fill it 23 const writable = self.fifo.writableSlice(0); 24 assert(writable.len > 0); 25 const n = try self.unbuffered_reader.read(writable); 26 if (n == 0) { 27 // reading from the unbuffered stream returned nothing 28 // so we have nothing left to read. 29 return dest_index; 30 } 31 self.fifo.update(n); 32 } 33 dest_index += written; 34 } 35 return dest.len; 36 } 37 38 pub fn reader(self: *Self) Reader { 39 return .{ .context = self }; 40 } 41 }; 42} 43 44pub fn bufferedReader(underlying_stream: anytype) BufferedReader(4096, @TypeOf(underlying_stream)) { 45 return .{ .unbuffered_reader = underlying_stream }; 46} 47 48test "io.BufferedReader" { 49 const OneByteReadReader = struct { 50 str: []const u8, 51 curr: usize, 52 53 const Error = error{NoError}; 54 const Self = @This(); 55 const Reader = io.Reader(*Self, Error, read); 56 57 fn init(str: []const u8) Self { 58 return Self{ 59 .str = str, 60 .curr = 0, 61 }; 62 } 63 64 fn read(self: *Self, dest: []u8) Error!usize { 65 if (self.str.len <= self.curr or dest.len == 0) 66 return 0; 67 68 dest[0] = self.str[self.curr]; 69 self.curr += 1; 70 return 1; 71 } 72 73 fn reader(self: *Self) Reader { 74 return .{ .context = self }; 75 } 76 }; 77 78 const str = "This is a test"; 79 var one_byte_stream = OneByteReadReader.init(str); 80 var buf_reader = bufferedReader(one_byte_stream.reader()); 81 const stream = buf_reader.reader(); 82 83 const res = try stream.readAllAlloc(testing.allocator, str.len + 1); 84 defer testing.allocator.free(res); 85 try testing.expectEqualSlices(u8, str, res); 86} 87