| ... | @@ -752,6 +752,11 @@ pub fn peekDelimiterInclusive(r: *Reader, delimiter: u8) DelimiterError![]u8 { | ... | @@ -752,6 +752,11 @@ pub fn peekDelimiterInclusive(r: *Reader, delimiter: u8) DelimiterError![]u8 { |
| 752 | @branchHint(.likely); | 752 | @branchHint(.likely); |
| 753 | return buffer[seek .. end + 1]; | 753 | return buffer[seek .. end + 1]; |
| 754 | } | 754 | } |
| | 755 | if (r.vtable.stream == &endingStream) { |
| | 756 | // Protect the `@constCast` of `fixed`. |
| | 757 | return error.EndOfStream; |
| | 758 | } |
| | 759 | r.rebase(); |
| 755 | while (r.buffer.len - r.end != 0) { | 760 | while (r.buffer.len - r.end != 0) { |
| 756 | const end_cap = r.buffer[r.end..]; | 761 | const end_cap = r.buffer[r.end..]; |
| 757 | var writer: Writer = .fixed(end_cap); | 762 | var writer: Writer = .fixed(end_cap); |
| ... | @@ -761,29 +766,9 @@ pub fn peekDelimiterInclusive(r: *Reader, delimiter: u8) DelimiterError![]u8 { | ... | @@ -761,29 +766,9 @@ pub fn peekDelimiterInclusive(r: *Reader, delimiter: u8) DelimiterError![]u8 { |
| 761 | }; | 766 | }; |
| 762 | r.end += n; | 767 | r.end += n; |
| 763 | if (std.mem.indexOfScalarPos(u8, end_cap[0..n], 0, delimiter)) |end| { | 768 | if (std.mem.indexOfScalarPos(u8, end_cap[0..n], 0, delimiter)) |end| { |
| 764 | return r.buffer[seek .. r.end - n + end + 1]; | 769 | return r.buffer[0 .. r.end - n + end + 1]; |
| 765 | } | 770 | } |
| 766 | } | 771 | } |
| 767 | var i: usize = 0; | | |
| 768 | while (seek - i != 0) { | | |
| 769 | const begin_cap = r.buffer[i..seek]; | | |
| 770 | var writer: Writer = .fixed(begin_cap); | | |
| 771 | const n = r.vtable.stream(r, &writer, .limited(begin_cap.len)) catch |err| switch (err) { | | |
| 772 | error.WriteFailed => unreachable, | | |
| 773 | else => |e| return e, | | |
| 774 | }; | | |
| 775 | i += n; | | |
| 776 | if (std.mem.indexOfScalarPos(u8, r.buffer[0..seek], i, delimiter)) |end| { | | |
| 777 | std.mem.rotate(u8, r.buffer, seek); | | |
| 778 | r.seek = 0; | | |
| 779 | r.end += i; | | |
| 780 | return r.buffer[0 .. seek + end + 1]; | | |
| 781 | } | | |
| 782 | } else if (i != 0) { | | |
| 783 | std.mem.rotate(u8, r.buffer, seek); | | |
| 784 | r.seek = 0; | | |
| 785 | r.end += i; | | |
| 786 | } | | |
| 787 | return error.StreamTooLong; | 772 | return error.StreamTooLong; |
| 788 | } | 773 | } |
| 789 | | 774 | |
| ... | @@ -1665,6 +1650,23 @@ test "readAlloc when the backing reader provides one byte at a time" { | ... | @@ -1665,6 +1650,23 @@ test "readAlloc when the backing reader provides one byte at a time" { |
| 1665 | try std.testing.expectEqualStrings(str, res); | 1650 | try std.testing.expectEqualStrings(str, res); |
| 1666 | } | 1651 | } |
| 1667 | | 1652 | |
| | 1653 | test "takeDelimiterInclusive when it rebases" { |
| | 1654 | const written_line = "ABCDEFGHIJKLMNOPQRSTUVWXYZ\n"; |
| | 1655 | var buffer: [128]u8 = undefined; |
| | 1656 | var tr: std.testing.Reader = .init(&buffer, &.{ |
| | 1657 | .{ .buffer = written_line }, |
| | 1658 | .{ .buffer = written_line }, |
| | 1659 | .{ .buffer = written_line }, |
| | 1660 | .{ .buffer = written_line }, |
| | 1661 | .{ .buffer = written_line }, |
| | 1662 | .{ .buffer = written_line }, |
| | 1663 | }); |
| | 1664 | const r = &tr.interface; |
| | 1665 | for (0..6) |_| { |
| | 1666 | try std.testing.expectEqualStrings(written_line, try r.takeDelimiterInclusive('\n')); |
| | 1667 | } |
| | 1668 | } |
| | 1669 | |
| 1668 | /// Provides a `Reader` implementation by passing data from an underlying | 1670 | /// Provides a `Reader` implementation by passing data from an underlying |
| 1669 | /// reader through `Hasher.update`. | 1671 | /// reader through `Hasher.update`. |
| 1670 | /// | 1672 | /// |