| ... | ... | @@ -343,23 +343,24 @@ pub fn BufferedInStreamCustom(comptime buffer_size: usize, comptime Error: type) |
| 343 | 343 | const amt_buffered = self.end_index - self.start_index; |
| 344 | 344 | if (amt_buffered == 0) { |
| 345 | 345 | assert(self.end_index <= buffer_size); |
| 346 | | if (self.end_index == buffer_size) { |
| 347 | | // we can read more data from the unbuffered stream |
| 348 | | if (dest_space < buffer_size) { |
| 349 | | self.start_index = 0; |
| 350 | | self.end_index = try self.unbuffered_in_stream.read(self.buffer[0..]); |
| 351 | | } else { |
| 352 | | // asking for so much data that buffering is actually less efficient. |
| 353 | | // forward the request directly to the unbuffered stream |
| 354 | | const amt_read = try self.unbuffered_in_stream.read(dest[dest_index..]); |
| 355 | | return dest_index + amt_read; |
| 356 | | } |
| 357 | | } else { |
| 358 | | // reading from the unbuffered stream returned less than we asked for |
| 359 | | // so we cannot read any more data. |
| 346 | // Make sure the last read actually gave us some data |
| 347 | if (self.end_index == 0) { |
| 348 | // reading from the unbuffered stream returned nothing |
| 349 | // so we have nothing left to read. |
| 360 | 350 | return dest_index; |
| 361 | 351 | } |
| 352 | // we can read more data from the unbuffered stream |
| 353 | if (dest_space < buffer_size) { |
| 354 | self.start_index = 0; |
| 355 | self.end_index = try self.unbuffered_in_stream.read(self.buffer[0..]); |
| 356 | } else { |
| 357 | // asking for so much data that buffering is actually less efficient. |
| 358 | // forward the request directly to the unbuffered stream |
| 359 | const amt_read = try self.unbuffered_in_stream.read(dest[dest_index..]); |
| 360 | return dest_index + amt_read; |
| 361 | } |
| 362 | 362 | } |
| 363 | |
| 363 | 364 | const copy_amount = math.min(dest_space, amt_buffered); |
| 364 | 365 | const copy_end_index = self.start_index + copy_amount; |
| 365 | 366 | mem.copy(u8, dest[dest_index..], self.buffer[self.start_index..copy_end_index]); |
| ... | ... | @@ -370,6 +371,46 @@ pub fn BufferedInStreamCustom(comptime buffer_size: usize, comptime Error: type) |
| 370 | 371 | }; |
| 371 | 372 | } |
| 372 | 373 | |
| 374 | test "io.BufferedInStream" { |
| 375 | const OneByteReadInStream = struct { |
| 376 | const Error = error{NoError}; |
| 377 | const Stream = InStream(Error); |
| 378 | |
| 379 | stream: Stream, |
| 380 | str: []const u8, |
| 381 | curr: usize, |
| 382 | |
| 383 | fn init(str: []const u8) @This() { |
| 384 | return @This(){ |
| 385 | .stream = Stream{ .readFn = readFn }, |
| 386 | .str = str, |
| 387 | .curr = 0, |
| 388 | }; |
| 389 | } |
| 390 | |
| 391 | fn readFn(in_stream: *Stream, dest: []u8) Error!usize { |
| 392 | const self = @fieldParentPtr(@This(), "stream", in_stream); |
| 393 | if (self.str.len <= self.curr or dest.len == 0) |
| 394 | return 0; |
| 395 | |
| 396 | dest[0] = self.str[self.curr]; |
| 397 | self.curr += 1; |
| 398 | return 1; |
| 399 | } |
| 400 | }; |
| 401 | |
| 402 | var buf: [100]u8 = undefined; |
| 403 | const allocator = &std.heap.FixedBufferAllocator.init(buf[0..]).allocator; |
| 404 | |
| 405 | const str = "This is a test"; |
| 406 | var one_byte_stream = OneByteReadInStream.init(str); |
| 407 | var buf_in_stream = BufferedInStream(OneByteReadInStream.Error).init(&one_byte_stream.stream); |
| 408 | const stream = &buf_in_stream.stream; |
| 409 | |
| 410 | const res = try stream.readAllAlloc(allocator, str.len + 1); |
| 411 | debug.assertOrPanic(mem.eql(u8, str, res)); |
| 412 | } |
| 413 | |
| 373 | 414 | /// Creates a stream which supports 'un-reading' data, so that it can be read again. |
| 374 | 415 | /// This makes look-ahead style parsing much easier. |
| 375 | 416 | pub fn PeekStream(comptime buffer_size: usize, comptime InStreamError: type) type { |
| ... | ... | @@ -1411,3 +1452,4 @@ test "import io tests" { |
| 1411 | 1452 | _ = @import("io_test.zig"); |
| 1412 | 1453 | } |
| 1413 | 1454 | } |
| 1455 | |