zig/lib/std/io/buffered_in_stream.zig
2020-03-10 18:44:30 -04:00

87 lines
2.7 KiB
Zig

const std = @import("../std.zig");
const io = std.io;
const assert = std.debug.assert;
const testing = std.testing;
pub fn BufferedInStream(comptime buffer_size: usize, comptime InStreamType: type) type {
return struct {
unbuffered_in_stream: InStreamType,
fifo: FifoType = FifoType.init(),
pub const Error = InStreamType.Error;
pub const InStream = io.InStream(*Self, Error, read);
const Self = @This();
const FifoType = std.fifo.LinearFifo(u8, std.fifo.LinearFifoBufferType{ .Static = buffer_size });
pub fn read(self: *Self, dest: []u8) Error!usize {
var dest_index: usize = 0;
while (dest_index < dest.len) {
const written = self.fifo.read(dest[dest_index..]);
if (written == 0) {
// fifo empty, fill it
const writable = self.fifo.writableSlice(0);
assert(writable.len > 0);
const n = try self.unbuffered_in_stream.read(writable);
if (n == 0) {
// reading from the unbuffered stream returned nothing
// so we have nothing left to read.
return dest_index;
}
self.fifo.update(n);
}
dest_index += written;
}
return dest.len;
}
pub fn inStream(self: *Self) InStream {
return .{ .context = self };
}
};
}
pub fn bufferedInStream(underlying_stream: var) BufferedInStream(4096, @TypeOf(underlying_stream)) {
return .{ .unbuffered_in_stream = underlying_stream };
}
test "io.BufferedInStream" {
const OneByteReadInStream = struct {
str: []const u8,
curr: usize,
const Error = error{NoError};
const Self = @This();
const InStream = io.InStream(*Self, Error, read);
fn init(str: []const u8) Self {
return Self{
.str = str,
.curr = 0,
};
}
fn read(self: *Self, dest: []u8) Error!usize {
if (self.str.len <= self.curr or dest.len == 0)
return 0;
dest[0] = self.str[self.curr];
self.curr += 1;
return 1;
}
fn inStream(self: *Self) InStream {
return .{ .context = self };
}
};
const str = "This is a test";
var one_byte_stream = OneByteReadInStream.init(str);
var buf_in_stream = bufferedInStream(one_byte_stream.inStream());
const stream = buf_in_stream.inStream();
const res = try stream.readAllAlloc(testing.allocator, str.len + 1);
defer testing.allocator.free(res);
testing.expectEqualSlices(u8, str, res);
}