| ... | ... | @@ -593,48 +593,29 @@ pub fn readSliceAll(r: *Reader, buffer: []u8) Error!void { |
| 593 | 593 | /// See also: |
| 594 | 594 | /// * `readSliceAll` |
| 595 | 595 | pub fn readSliceShort(r: *Reader, buffer: []u8) ShortError!usize { |
| 596 | | const in_buffer = r.buffer[r.seek..r.end]; |
| 597 | | const copy_len = @min(buffer.len, in_buffer.len); |
| 598 | | @memcpy(buffer[0..copy_len], in_buffer[0..copy_len]); |
| 599 | | if (buffer.len - copy_len == 0) { |
| 600 | | r.seek += copy_len; |
| 601 | | return buffer.len; |
| 602 | | } |
| 603 | | var i: usize = copy_len; |
| 604 | | r.end = 0; |
| 605 | | r.seek = 0; |
| 596 | var i: usize = 0; |
| 606 | 597 | while (true) { |
| 598 | const buffer_contents = r.buffer[r.seek..r.end]; |
| 599 | const dest = buffer[i..]; |
| 600 | const copy_len = @min(dest.len, buffer_contents.len); |
| 601 | @memcpy(dest[0..copy_len], buffer_contents[0..copy_len]); |
| 602 | if (dest.len - copy_len == 0) { |
| 603 | @branchHint(.likely); |
| 604 | r.seek += copy_len; |
| 605 | return buffer.len; |
| 606 | } |
| 607 | i += copy_len; |
| 608 | r.end = 0; |
| 609 | r.seek = 0; |
| 607 | 610 | const remaining = buffer[i..]; |
| 608 | | var wrapper: Writer.VectorWrapper = .{ |
| 609 | | .it = .{ |
| 610 | | .first = remaining, |
| 611 | | .last = r.buffer, |
| 612 | | }, |
| 613 | | .writer = .{ |
| 614 | | .buffer = if (remaining.len >= r.buffer.len) remaining else r.buffer, |
| 615 | | .vtable = Writer.VectorWrapper.vtable, |
| 616 | | }, |
| 617 | | }; |
| 618 | | const n = r.vtable.stream(r, &wrapper.writer, .unlimited) catch |err| switch (err) { |
| 619 | | error.WriteFailed => { |
| 620 | | if (!wrapper.used) { |
| 621 | | assert(r.seek == 0); |
| 622 | | r.seek = remaining.len; |
| 623 | | r.end = wrapper.writer.end; |
| 624 | | @memcpy(remaining, r.buffer[0..remaining.len]); |
| 625 | | } |
| 626 | | return buffer.len; |
| 627 | | }, |
| 611 | const new_remaining_len = readVecInner(r, &.{}, remaining, remaining.len) catch |err| switch (err) { |
| 628 | 612 | error.EndOfStream => return i, |
| 629 | 613 | error.ReadFailed => return error.ReadFailed, |
| 630 | 614 | }; |
| 631 | | if (n < remaining.len) { |
| 632 | | i += n; |
| 633 | | continue; |
| 634 | | } |
| 635 | | r.end = n - remaining.len; |
| 636 | | return buffer.len; |
| 615 | if (new_remaining_len == 0) return buffer.len; |
| 616 | i += remaining.len - new_remaining_len; |
| 637 | 617 | } |
| 618 | return buffer.len; |
| 638 | 619 | } |
| 639 | 620 | |
| 640 | 621 | /// Fill `buffer` with the next `buffer.len` bytes from the stream, advancing |
| ... | ... | @@ -1640,6 +1621,19 @@ test readSliceShort { |
| 1640 | 1621 | try testing.expectEqual(0, try r.readSliceShort(&buf)); |
| 1641 | 1622 | } |
| 1642 | 1623 | |
| 1624 | test "readSliceShort with smaller buffer than Reader" { |
| 1625 | var reader_buf: [15]u8 = undefined; |
| 1626 | const str = "This is a test"; |
| 1627 | var one_byte_stream: testing.Reader = .init(&reader_buf, &.{ |
| 1628 | .{ .buffer = str }, |
| 1629 | }); |
| 1630 | one_byte_stream.artificial_limit = .limited(1); |
| 1631 | |
| 1632 | var buf: [14]u8 = undefined; |
| 1633 | try testing.expectEqual(14, try one_byte_stream.interface.readSliceShort(&buf)); |
| 1634 | try testing.expectEqualStrings(str, &buf); |
| 1635 | } |
| 1636 | |
| 1643 | 1637 | test readVec { |
| 1644 | 1638 | var r: Reader = .fixed(std.ascii.letters); |
| 1645 | 1639 | var flat_buffer: [52]u8 = undefined; |
| ... | ... | @@ -1702,33 +1696,13 @@ fn failingDiscard(r: *Reader, limit: Limit) Error!usize { |
| 1702 | 1696 | } |
| 1703 | 1697 | |
| 1704 | 1698 | test "readAlloc when the backing reader provides one byte at a time" { |
| 1705 | | const OneByteReader = struct { |
| 1706 | | str: []const u8, |
| 1707 | | i: usize, |
| 1708 | | reader: Reader, |
| 1709 | | |
| 1710 | | fn stream(r: *Reader, w: *Writer, limit: Limit) StreamError!usize { |
| 1711 | | assert(@intFromEnum(limit) >= 1); |
| 1712 | | const self: *@This() = @fieldParentPtr("reader", r); |
| 1713 | | if (self.str.len - self.i == 0) return error.EndOfStream; |
| 1714 | | try w.writeByte(self.str[self.i]); |
| 1715 | | self.i += 1; |
| 1716 | | return 1; |
| 1717 | | } |
| 1718 | | }; |
| 1719 | 1699 | const str = "This is a test"; |
| 1720 | 1700 | var tiny_buffer: [1]u8 = undefined; |
| 1721 | | var one_byte_stream: OneByteReader = .{ |
| 1722 | | .str = str, |
| 1723 | | .i = 0, |
| 1724 | | .reader = .{ |
| 1725 | | .buffer = &tiny_buffer, |
| 1726 | | .vtable = &.{ .stream = OneByteReader.stream }, |
| 1727 | | .seek = 0, |
| 1728 | | .end = 0, |
| 1729 | | }, |
| 1730 | | }; |
| 1731 | | const res = try one_byte_stream.reader.allocRemaining(std.testing.allocator, .unlimited); |
| 1701 | var one_byte_stream: testing.Reader = .init(&tiny_buffer, &.{ |
| 1702 | .{ .buffer = str }, |
| 1703 | }); |
| 1704 | one_byte_stream.artificial_limit = .limited(1); |
| 1705 | const res = try one_byte_stream.interface.allocRemaining(std.testing.allocator, .unlimited); |
| 1732 | 1706 | defer std.testing.allocator.free(res); |
| 1733 | 1707 | try std.testing.expectEqualStrings(str, res); |
| 1734 | 1708 | } |