| ... | ... | @@ -763,13 +763,14 @@ pub fn takeDelimiterInclusive(r: *Reader, delimiter: u8) DelimiterError![]u8 { |
| 763 | 763 | pub fn peekDelimiterInclusive(r: *Reader, delimiter: u8) DelimiterError![]u8 { |
| 764 | 764 | const buffer = r.buffer[0..r.end]; |
| 765 | 765 | const seek = r.seek; |
| 766 | | if (std.mem.indexOfScalarPos(u8, buffer, seek, delimiter)) |end| { |
| 766 | if (std.mem.indexOfScalarPos(u8, buffer, seek, delimiter)) |delimiter_index| { |
| 767 | 767 | @branchHint(.likely); |
| 768 | | return buffer[seek .. end + 1]; |
| 768 | return buffer[seek .. delimiter_index + 1]; |
| 769 | 769 | } |
| 770 | 770 | // TODO take a parameter for max search length rather than relying on buffer capacity |
| 771 | 771 | try rebase(r, r.buffer.len); |
| 772 | 772 | while (r.buffer.len - r.end != 0) { |
| 773 | const existing_buffered_len = r.end - r.seek; |
| 773 | 774 | const end_cap = r.buffer[r.end..]; |
| 774 | 775 | var writer: Writer = .fixed(end_cap); |
| 775 | 776 | const n = r.vtable.stream(r, &writer, .limited(end_cap.len)) catch |err| switch (err) { |
| ... | ... | @@ -777,8 +778,8 @@ pub fn peekDelimiterInclusive(r: *Reader, delimiter: u8) DelimiterError![]u8 { |
| 777 | 778 | else => |e| return e, |
| 778 | 779 | }; |
| 779 | 780 | r.end += n; |
| 780 | | if (std.mem.indexOfScalarPos(u8, end_cap[0..n], 0, delimiter)) |end| { |
| 781 | | return r.buffer[0 .. r.end - n + end + 1]; |
| 781 | if (std.mem.indexOfScalarPos(u8, r.buffer[0..r.end], r.seek + existing_buffered_len, delimiter)) |delimiter_index| { |
| 782 | return r.buffer[r.seek .. delimiter_index + 1]; |
| 782 | 783 | } |
| 783 | 784 | } |
| 784 | 785 | return error.StreamTooLong; |
| ... | ... | @@ -1534,6 +1535,18 @@ test "readSliceShort with smaller buffer than Reader" { |
| 1534 | 1535 | try testing.expectEqualStrings(str, &buf); |
| 1535 | 1536 | } |
| 1536 | 1537 | |
| 1538 | test "readSliceShort with indirect reader" { |
| 1539 | var r: Reader = .fixed("HelloFren"); |
| 1540 | var ri_buf: [3]u8 = undefined; |
| 1541 | var ri: std.testing.ReaderIndirect = .init(&r, &ri_buf); |
| 1542 | var buf: [5]u8 = undefined; |
| 1543 | try testing.expectEqual(5, try ri.interface.readSliceShort(&buf)); |
| 1544 | try testing.expectEqualStrings("Hello", buf[0..5]); |
| 1545 | try testing.expectEqual(4, try ri.interface.readSliceShort(&buf)); |
| 1546 | try testing.expectEqualStrings("Fren", buf[0..4]); |
| 1547 | try testing.expectEqual(0, try ri.interface.readSliceShort(&buf)); |
| 1548 | } |
| 1549 | |
| 1537 | 1550 | test readVec { |
| 1538 | 1551 | var r: Reader = .fixed(std.ascii.letters); |
| 1539 | 1552 | var flat_buffer: [52]u8 = undefined; |
| ... | ... | @@ -1643,6 +1656,26 @@ test "takeDelimiterInclusive when it rebases" { |
| 1643 | 1656 | } |
| 1644 | 1657 | } |
| 1645 | 1658 | |
| 1659 | test "takeDelimiterInclusive on an indirect reader when it rebases" { |
| 1660 | const written_line = "ABCDEFGHIJKLMNOPQRSTUVWXYZ\n"; |
| 1661 | var buffer: [128]u8 = undefined; |
| 1662 | var tr: std.testing.Reader = .init(&buffer, &.{ |
| 1663 | .{ .buffer = written_line[0..4] }, |
| 1664 | .{ .buffer = written_line[4..] }, |
| 1665 | .{ .buffer = written_line }, |
| 1666 | .{ .buffer = written_line }, |
| 1667 | .{ .buffer = written_line }, |
| 1668 | .{ .buffer = written_line }, |
| 1669 | .{ .buffer = written_line }, |
| 1670 | }); |
| 1671 | var indirect_buffer: [128]u8 = undefined; |
| 1672 | var tri: std.testing.ReaderIndirect = .init(&tr.interface, &indirect_buffer); |
| 1673 | const r = &tri.interface; |
| 1674 | for (0..6) |_| { |
| 1675 | try std.testing.expectEqualStrings(written_line, try r.takeDelimiterInclusive('\n')); |
| 1676 | } |
| 1677 | } |
| 1678 | |
| 1646 | 1679 | test "takeStruct and peekStruct packed" { |
| 1647 | 1680 | var r: Reader = .fixed(&.{ 0b11110000, 0b00110011 }); |
| 1648 | 1681 | const S = packed struct(u16) { a: u2, b: u6, c: u7, d: u1 }; |