Commit 5784500572

Andrew Kelley <andrew@ziglang.org>
2025-07-17 08:43:46
std.Io.Reader: fix readSliceShort with smaller buffer than Reader
closes #24443
1 parent 86699ac
Changed files (1)
lib
std
lib/std/Io/Reader.zig
@@ -593,48 +593,29 @@ pub fn readSliceAll(r: *Reader, buffer: []u8) Error!void {
 /// See also:
 /// * `readSliceAll`
 pub fn readSliceShort(r: *Reader, buffer: []u8) ShortError!usize {
-    const in_buffer = r.buffer[r.seek..r.end];
-    const copy_len = @min(buffer.len, in_buffer.len);
-    @memcpy(buffer[0..copy_len], in_buffer[0..copy_len]);
-    if (buffer.len - copy_len == 0) {
-        r.seek += copy_len;
-        return buffer.len;
-    }
-    var i: usize = copy_len;
-    r.end = 0;
-    r.seek = 0;
+    var i: usize = 0;
     while (true) {
+        const buffer_contents = r.buffer[r.seek..r.end];
+        const dest = buffer[i..];
+        const copy_len = @min(dest.len, buffer_contents.len);
+        @memcpy(dest[0..copy_len], buffer_contents[0..copy_len]);
+        if (dest.len - copy_len == 0) {
+            @branchHint(.likely);
+            r.seek += copy_len;
+            return buffer.len;
+        }
+        i += copy_len;
+        r.end = 0;
+        r.seek = 0;
         const remaining = buffer[i..];
-        var wrapper: Writer.VectorWrapper = .{
-            .it = .{
-                .first = remaining,
-                .last = r.buffer,
-            },
-            .writer = .{
-                .buffer = if (remaining.len >= r.buffer.len) remaining else r.buffer,
-                .vtable = Writer.VectorWrapper.vtable,
-            },
-        };
-        const n = r.vtable.stream(r, &wrapper.writer, .unlimited) catch |err| switch (err) {
-            error.WriteFailed => {
-                if (!wrapper.used) {
-                    assert(r.seek == 0);
-                    r.seek = remaining.len;
-                    r.end = wrapper.writer.end;
-                    @memcpy(remaining, r.buffer[0..remaining.len]);
-                }
-                return buffer.len;
-            },
+        const new_remaining_len = readVecInner(r, &.{}, remaining, remaining.len) catch |err| switch (err) {
             error.EndOfStream => return i,
             error.ReadFailed => return error.ReadFailed,
         };
-        if (n < remaining.len) {
-            i += n;
-            continue;
-        }
-        r.end = n - remaining.len;
-        return buffer.len;
+        if (new_remaining_len == 0) return buffer.len;
+        i += remaining.len - new_remaining_len;
     }
+    return buffer.len;
 }
 
 /// Fill `buffer` with the next `buffer.len` bytes from the stream, advancing
@@ -1640,6 +1621,19 @@ test readSliceShort {
     try testing.expectEqual(0, try r.readSliceShort(&buf));
 }
 
+test "readSliceShort with smaller buffer than Reader" {
+    var reader_buf: [15]u8 = undefined;
+    const str = "This is a test";
+    var one_byte_stream: testing.Reader = .init(&reader_buf, &.{
+        .{ .buffer = str },
+    });
+    one_byte_stream.artificial_limit = .limited(1);
+
+    var buf: [14]u8 = undefined;
+    try testing.expectEqual(14, try one_byte_stream.interface.readSliceShort(&buf));
+    try testing.expectEqualStrings(str, &buf);
+}
+
 test readVec {
     var r: Reader = .fixed(std.ascii.letters);
     var flat_buffer: [52]u8 = undefined;