authorgravatar for squeek502@hotmail.comRyan Liptak <squeek502@hotmail.com> 2026-09-15 15:18:34-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-09-16 07:31:00+02:00
log2ec5523d5a70db80bac8563e1f06d3b164f53db3
treeb5cc7204b7190c8f968335b94843c30e9cb1862e
parent5c4b14b6828b6de047a00e342de354cb69367f72

Reader.allocRemaining: only error with StreamTooLong when limit is exceeded

Follow up to #36708 and #36692. The intended behavior of this function was what was previously documented: that StreamTooLong was only returned when the limit was *exceeded*. However, that was never implemented. This commit implements the intended behavior, with the added caveat that `limit + 1` bytes will be discarded if the limit is exceeded.

1 files changed, 33 insertions(+), 4 deletions(-)

lib/std/Io/Reader.zig+33-4
......@@ -287,16 +287,20 @@ pub const LimitedAllocError = Allocator.Error || ShortError || error{StreamTooLo
287287/// Transfers all bytes from the current position to the end of the stream, up
288288/// to `limit`, returning them as a caller-owned allocated slice.
289289///
290/// If `limit` is reached or exceeded, `error.StreamTooLong` is returned
291/// instead. In such case, the next byte that would be read will be the first
292/// one to exceed `limit`, and all preceeding bytes have been discarded.
290/// If `limit` is exceeded, `error.StreamTooLong` is returned instead.
291/// In such case, the next byte that would be read will be one byte past the
292/// first one to exceed `limit`, and all preceeding bytes have been discarded.
293293///
294294/// See also:
295295/// * `appendRemaining`
296296pub fn allocRemaining(r: *Reader, gpa: Allocator, limit: Limit) LimitedAllocError![]u8 {
297297 var buffer: ArrayList(u8) = .empty;
298298 defer buffer.deinit(gpa);
299 try appendRemaining(r, gpa, &buffer, limit);
299
300 try appendRemaining(r, gpa, &buffer, switch (limit) {
301 .unlimited => limit,
302 .nothing, _ => .limited(@backingInt(limit) + 1),
303 });
300304 return buffer.toOwnedSlice(gpa);
301305}
302306
......@@ -1894,6 +1898,31 @@ test "takeStruct and peekStruct packed" {
18941898 try testing.expectError(error.EndOfStream, r.takeStruct(S, .little));
18951899}
18961900
1901test allocRemaining {
1902 {
1903 var r: Reader = .fixed("abc");
1904 const str = try r.allocRemaining(testing.allocator, .unlimited);
1905 defer testing.allocator.free(str);
1906 try testing.expectEqualStrings("abc", str);
1907 }
1908 {
1909 var r: Reader = .fixed("abc");
1910 const str = try r.allocRemaining(testing.allocator, .limited(5));
1911 defer testing.allocator.free(str);
1912 try testing.expectEqualStrings("abc", str);
1913 }
1914 {
1915 var r: Reader = .fixed("abc");
1916 const str = try r.allocRemaining(testing.allocator, .limited(3));
1917 defer testing.allocator.free(str);
1918 try testing.expectEqualStrings("abc", str);
1919 }
1920 {
1921 var r: Reader = .fixed("abcd");
1922 try testing.expectError(error.StreamTooLong, r.allocRemaining(testing.allocator, .limited(3)));
1923 }
1924}
1925
18971926/// Provides a `Reader` implementation by passing data from an underlying
18981927/// reader through `Hasher.update`.
18991928///