authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-09 16:59:34-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-09 17:18:23-07:00
logc072cf2bb8120f247f9af0095b6e5ad8fe1fbcd6
tree1c2d3915e36fbf3aa6b117667233059eb7bc4318
parent93ac76594a6ee88e0851bca904a2bbfb0c6509d7

std.io.Reader.peekDelimiterInclusive: simplify and fix


2 files changed, 63 insertions(+), 21 deletions(-)

lib/std/io/Reader.zig+23-21
......@@ -752,6 +752,11 @@ pub fn peekDelimiterInclusive(r: *Reader, delimiter: u8) DelimiterError![]u8 {
752752 @branchHint(.likely);
753753 return buffer[seek .. end + 1];
754754 }
755 if (r.vtable.stream == &endingStream) {
756 // Protect the `@constCast` of `fixed`.
757 return error.EndOfStream;
758 }
759 r.rebase();
755760 while (r.buffer.len - r.end != 0) {
756761 const end_cap = r.buffer[r.end..];
757762 var writer: Writer = .fixed(end_cap);
......@@ -761,29 +766,9 @@ pub fn peekDelimiterInclusive(r: *Reader, delimiter: u8) DelimiterError![]u8 {
761766 };
762767 r.end += n;
763768 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];
765770 }
766771 }
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 }
787772 return error.StreamTooLong;
788773}
789774
......@@ -1665,6 +1650,23 @@ test "readAlloc when the backing reader provides one byte at a time" {
16651650 try std.testing.expectEqualStrings(str, res);
16661651}
16671652
1653test "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
16681670/// Provides a `Reader` implementation by passing data from an underlying
16691671/// reader through `Hasher.update`.
16701672///
lib/std/testing.zig+40
......@@ -1206,3 +1206,43 @@ pub inline fn fuzz(
12061206) anyerror!void {
12071207 return @import("root").fuzz(context, testOne, options);
12081208}
1209
1210/// A `std.io.Reader` that writes a predetermined list of buffers during `stream`.
1211pub const Reader = struct {
1212 calls: []const Call,
1213 interface: std.io.Reader,
1214 next_call_index: usize,
1215 next_offset: usize,
1216
1217 pub const Call = struct {
1218 buffer: []const u8,
1219 };
1220
1221 pub fn init(buffer: []u8, calls: []const Call) Reader {
1222 return .{
1223 .next_call_index = 0,
1224 .next_offset = 0,
1225 .interface = .{
1226 .vtable = &.{ .stream = stream },
1227 .buffer = buffer,
1228 .seek = 0,
1229 .end = 0,
1230 },
1231 .calls = calls,
1232 };
1233 }
1234
1235 fn stream(io_r: *std.io.Reader, w: *std.io.Writer, limit: std.io.Limit) std.io.Reader.StreamError!usize {
1236 const r: *Reader = @alignCast(@fieldParentPtr("interface", io_r));
1237 if (r.calls.len - r.next_call_index == 0) return error.EndOfStream;
1238 const call = r.calls[r.next_call_index];
1239 const buffer = limit.sliceConst(call.buffer[r.next_offset..]);
1240 const n = try w.write(buffer);
1241 r.next_offset += n;
1242 if (call.buffer.len - r.next_offset == 0) {
1243 r.next_call_index += 1;
1244 r.next_offset = 0;
1245 }
1246 return n;
1247 }
1248};