| ... | @@ -343,23 +343,24 @@ pub fn BufferedInStreamCustom(comptime buffer_size: usize, comptime Error: type) | ... | @@ -343,23 +343,24 @@ pub fn BufferedInStreamCustom(comptime buffer_size: usize, comptime Error: type) |
| 343 | const amt_buffered = self.end_index - self.start_index; | 343 | const amt_buffered = self.end_index - self.start_index; |
| 344 | if (amt_buffered == 0) { | 344 | if (amt_buffered == 0) { |
| 345 | assert(self.end_index <= buffer_size); | 345 | assert(self.end_index <= buffer_size); |
| 346 | if (self.end_index == buffer_size) { | 346 | // Make sure the last read actually gave us some data |
| 347 | // we can read more data from the unbuffered stream | 347 | if (self.end_index == 0) { |
| 348 | if (dest_space < buffer_size) { | 348 | // reading from the unbuffered stream returned nothing |
| 349 | self.start_index = 0; | 349 | // so we have nothing left to read. |
| 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. | | |
| 360 | return dest_index; | 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 | const copy_amount = math.min(dest_space, amt_buffered); | 364 | const copy_amount = math.min(dest_space, amt_buffered); |
| 364 | const copy_end_index = self.start_index + copy_amount; | 365 | const copy_end_index = self.start_index + copy_amount; |
| 365 | mem.copy(u8, dest[dest_index..], self.buffer[self.start_index..copy_end_index]); | 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,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 | /// Creates a stream which supports 'un-reading' data, so that it can be read again. | 414 | /// Creates a stream which supports 'un-reading' data, so that it can be read again. |
| 374 | /// This makes look-ahead style parsing much easier. | 415 | /// This makes look-ahead style parsing much easier. |
| 375 | pub fn PeekStream(comptime buffer_size: usize, comptime InStreamError: type) type { | 416 | pub fn PeekStream(comptime buffer_size: usize, comptime InStreamError: type) type { |
| ... | @@ -1411,3 +1452,4 @@ test "import io tests" { | ... | @@ -1411,3 +1452,4 @@ test "import io tests" { |
| 1411 | _ = @import("io_test.zig"); | 1452 | _ = @import("io_test.zig"); |
| 1412 | } | 1453 | } |
| 1413 | } | 1454 | } |
| | 1455 | |