| ... | @@ -795,13 +795,14 @@ pub fn takeDelimiterInclusive(r: *Reader, delimiter: u8) DelimiterError![]u8 { | ... | @@ -795,13 +795,14 @@ pub fn takeDelimiterInclusive(r: *Reader, delimiter: u8) DelimiterError![]u8 { |
| 795 | pub fn peekDelimiterInclusive(r: *Reader, delimiter: u8) DelimiterError![]u8 { | 795 | pub fn peekDelimiterInclusive(r: *Reader, delimiter: u8) DelimiterError![]u8 { |
| 796 | const buffer = r.buffer[0..r.end]; | 796 | const buffer = r.buffer[0..r.end]; |
| 797 | const seek = r.seek; | 797 | const seek = r.seek; |
| 798 | if (std.mem.indexOfScalarPos(u8, buffer, seek, delimiter)) |end| { | 798 | if (std.mem.indexOfScalarPos(u8, buffer, seek, delimiter)) |delimiter_index| { |
| 799 | @branchHint(.likely); | 799 | @branchHint(.likely); |
| 800 | return buffer[seek .. end + 1]; | 800 | return buffer[seek .. delimiter_index + 1]; |
| 801 | } | 801 | } |
| 802 | // TODO take a parameter for max search length rather than relying on buffer capacity | 802 | // TODO take a parameter for max search length rather than relying on buffer capacity |
| 803 | try rebase(r, r.buffer.len); | 803 | try rebase(r, r.buffer.len); |
| 804 | while (r.buffer.len - r.end != 0) { | 804 | while (r.buffer.len - r.end != 0) { |
| | 805 | const existing_buffered_len = r.end - r.seek; |
| 805 | const end_cap = r.buffer[r.end..]; | 806 | const end_cap = r.buffer[r.end..]; |
| 806 | var writer: Writer = .fixed(end_cap); | 807 | var writer: Writer = .fixed(end_cap); |
| 807 | const n = r.vtable.stream(r, &writer, .limited(end_cap.len)) catch |err| switch (err) { | 808 | const n = r.vtable.stream(r, &writer, .limited(end_cap.len)) catch |err| switch (err) { |
| ... | @@ -809,8 +810,8 @@ pub fn peekDelimiterInclusive(r: *Reader, delimiter: u8) DelimiterError![]u8 { | ... | @@ -809,8 +810,8 @@ pub fn peekDelimiterInclusive(r: *Reader, delimiter: u8) DelimiterError![]u8 { |
| 809 | else => |e| return e, | 810 | else => |e| return e, |
| 810 | }; | 811 | }; |
| 811 | r.end += n; | 812 | r.end += n; |
| 812 | if (std.mem.indexOfScalarPos(u8, end_cap[0..n], 0, delimiter)) |end| { | 813 | if (std.mem.indexOfScalarPos(u8, r.buffer[0..r.end], r.seek + existing_buffered_len, delimiter)) |delimiter_index| { |
| 813 | return r.buffer[0 .. r.end - n + end + 1]; | 814 | return r.buffer[r.seek .. delimiter_index + 1]; |
| 814 | } | 815 | } |
| 815 | } | 816 | } |
| 816 | return error.StreamTooLong; | 817 | return error.StreamTooLong; |
| ... | @@ -1601,6 +1602,18 @@ test "readSliceShort with smaller buffer than Reader" { | ... | @@ -1601,6 +1602,18 @@ test "readSliceShort with smaller buffer than Reader" { |
| 1601 | try testing.expectEqualStrings(str, &buf); | 1602 | try testing.expectEqualStrings(str, &buf); |
| 1602 | } | 1603 | } |
| 1603 | | 1604 | |
| | 1605 | test "readSliceShort with indirect reader" { |
| | 1606 | var r: Reader = .fixed("HelloFren"); |
| | 1607 | var ri_buf: [3]u8 = undefined; |
| | 1608 | var ri: std.testing.ReaderIndirect = .init(&r, &ri_buf); |
| | 1609 | var buf: [5]u8 = undefined; |
| | 1610 | try testing.expectEqual(5, try ri.interface.readSliceShort(&buf)); |
| | 1611 | try testing.expectEqualStrings("Hello", buf[0..5]); |
| | 1612 | try testing.expectEqual(4, try ri.interface.readSliceShort(&buf)); |
| | 1613 | try testing.expectEqualStrings("Fren", buf[0..4]); |
| | 1614 | try testing.expectEqual(0, try ri.interface.readSliceShort(&buf)); |
| | 1615 | } |
| | 1616 | |
| 1604 | test readVec { | 1617 | test readVec { |
| 1605 | var r: Reader = .fixed(std.ascii.letters); | 1618 | var r: Reader = .fixed(std.ascii.letters); |
| 1606 | var flat_buffer: [52]u8 = undefined; | 1619 | var flat_buffer: [52]u8 = undefined; |
| ... | @@ -1701,6 +1714,26 @@ test "takeDelimiterInclusive when it rebases" { | ... | @@ -1701,6 +1714,26 @@ test "takeDelimiterInclusive when it rebases" { |
| 1701 | } | 1714 | } |
| 1702 | } | 1715 | } |
| 1703 | | 1716 | |
| | 1717 | test "takeDelimiterInclusive on an indirect reader when it rebases" { |
| | 1718 | const written_line = "ABCDEFGHIJKLMNOPQRSTUVWXYZ\n"; |
| | 1719 | var buffer: [128]u8 = undefined; |
| | 1720 | var tr: std.testing.Reader = .init(&buffer, &.{ |
| | 1721 | .{ .buffer = written_line[0..4] }, |
| | 1722 | .{ .buffer = written_line[4..] }, |
| | 1723 | .{ .buffer = written_line }, |
| | 1724 | .{ .buffer = written_line }, |
| | 1725 | .{ .buffer = written_line }, |
| | 1726 | .{ .buffer = written_line }, |
| | 1727 | .{ .buffer = written_line }, |
| | 1728 | }); |
| | 1729 | var indirect_buffer: [128]u8 = undefined; |
| | 1730 | var tri: std.testing.ReaderIndirect = .init(&tr.interface, &indirect_buffer); |
| | 1731 | const r = &tri.interface; |
| | 1732 | for (0..6) |_| { |
| | 1733 | try std.testing.expectEqualStrings(written_line, try r.takeDelimiterInclusive('\n')); |
| | 1734 | } |
| | 1735 | } |
| | 1736 | |
| 1704 | test "takeStruct and peekStruct packed" { | 1737 | test "takeStruct and peekStruct packed" { |
| 1705 | var r: Reader = .fixed(&.{ 0b11110000, 0b00110011 }); | 1738 | var r: Reader = .fixed(&.{ 0b11110000, 0b00110011 }); |
| 1706 | const S = packed struct(u16) { a: u2, b: u6, c: u7, d: u1 }; | 1739 | const S = packed struct(u16) { a: u2, b: u6, c: u7, d: u1 }; |