Commit 77e839e283
Changed files (1)
lib
std
lib/std/io/Reader.zig
@@ -846,37 +846,44 @@ pub fn peekDelimiterExclusive(r: *Reader, delimiter: u8) DelimiterError![]u8 {
/// Appends to `w` contents by reading from the stream until `delimiter` is
/// found. Does not write the delimiter itself.
///
-/// Returns number of bytes streamed.
-pub fn readDelimiter(r: *Reader, w: *Writer, delimiter: u8) StreamError!usize {
- const amount, const to = try r.readAny(w, delimiter, .unlimited);
- return switch (to) {
- .delimiter => amount,
- .limit => unreachable,
- .end => error.EndOfStream,
+/// Returns number of bytes streamed, which may be zero, or error.EndOfStream
+/// if the delimiter was not found.
+///
+/// See also:
+/// * `streamDelimiterEnding`
+/// * `streamDelimiterLimit`
+pub fn streamDelimiter(r: *Reader, w: *Writer, delimiter: u8) StreamError!usize {
+ const n = streamDelimiterLimit(r, w, delimiter, .unlimited) catch |err| switch (err) {
+ error.StreamTooLong => unreachable, // unlimited is passed
+ else => |e| return e,
};
+ if (r.seek == r.end) return error.EndOfStream;
+ return n;
}
/// Appends to `w` contents by reading from the stream until `delimiter` is found.
/// Does not write the delimiter itself.
///
-/// Succeeds if stream ends before delimiter found.
+/// Returns number of bytes streamed, which may be zero. End of stream can be
+/// detected by checking if the next byte in the stream is the delimiter.
///
-/// Returns number of bytes streamed. The end is not signaled to the writer.
-pub fn readDelimiterEnding(
+/// See also:
+/// * `streamDelimiter`
+/// * `streamDelimiterLimit`
+pub fn streamDelimiterEnding(
r: *Reader,
w: *Writer,
delimiter: u8,
) StreamRemainingError!usize {
- const amount, const to = try r.readAny(w, delimiter, .unlimited);
- return switch (to) {
- .delimiter, .end => amount,
- .limit => unreachable,
+ return streamDelimiterLimit(r, w, delimiter, .unlimited) catch |err| switch (err) {
+ error.StreamTooLong => unreachable, // unlimited is passed
+ else => |e| return e,
};
}
-pub const StreamDelimiterLimitedError = StreamRemainingError || error{
- /// Stream ended before the delimiter was found.
- EndOfStream,
+pub const StreamDelimiterLimitError = error{
+ ReadFailed,
+ WriteFailed,
/// The delimiter was not found within the limit.
StreamTooLong,
};
@@ -884,45 +891,31 @@ pub const StreamDelimiterLimitedError = StreamRemainingError || error{
/// Appends to `w` contents by reading from the stream until `delimiter` is found.
/// Does not write the delimiter itself.
///
-/// Returns number of bytes streamed.
-pub fn readDelimiterLimit(
+/// Returns number of bytes streamed, which may be zero. End of stream can be
+/// detected by checking if the next byte in the stream is the delimiter.
+pub fn streamDelimiterLimit(
r: *Reader,
w: *Writer,
delimiter: u8,
limit: Limit,
-) StreamDelimiterLimitedError!usize {
- const amount, const to = try r.readAny(w, delimiter, limit);
- return switch (to) {
- .delimiter => amount,
- .limit => error.StreamTooLong,
- .end => error.EndOfStream,
- };
-}
-
-fn readAny(
- r: *Reader,
- w: *Writer,
- delimiter: ?u8,
- limit: Limit,
-) StreamRemainingError!struct { usize, enum { delimiter, limit, end } } {
- var amount: usize = 0;
- var remaining = limit;
- while (remaining.nonzero()) {
- const available = remaining.slice(r.peekGreedy(1) catch |err| switch (err) {
- error.ReadFailed => |e| return e,
- error.EndOfStream => return .{ amount, .end },
+) StreamDelimiterLimitError!usize {
+ var remaining = @intFromEnum(limit);
+ while (remaining != 0) {
+ const available = Limit.limited(remaining).slice(r.peekGreedy(1) catch |err| switch (err) {
+ error.ReadFailed => return error.ReadFailed,
+ error.EndOfStream => return @intFromEnum(limit) - remaining,
});
- if (delimiter) |d| if (std.mem.indexOfScalar(u8, available, d)) |delimiter_index| {
+ if (std.mem.indexOfScalar(u8, available, delimiter)) |delimiter_index| {
try w.writeAll(available[0..delimiter_index]);
- r.toss(delimiter_index + 1);
- return .{ amount + delimiter_index, .delimiter };
- };
+ r.toss(delimiter_index);
+ remaining -= delimiter_index;
+ return @intFromEnum(limit) - remaining;
+ }
try w.writeAll(available);
r.toss(available.len);
- amount += available.len;
- remaining = remaining.subtract(available.len).?;
+ remaining -= available.len;
}
- return .{ amount, .limit };
+ return error.StreamTooLong;
}
/// Reads from the stream until specified byte is found, discarding all data,
@@ -1348,15 +1341,33 @@ test peekDelimiterExclusive {
try testing.expectEqualStrings("c", try r.peekDelimiterExclusive('\n'));
}
-test readDelimiter {
- return error.Unimplemented;
+test streamDelimiter {
+ var out_buffer: [10]u8 = undefined;
+ var r: Reader = .fixed("foo\nbars");
+ var w: Writer = .fixed(&out_buffer);
+ // Short streams are possible with this function but not with fixed.
+ try testing.expectEqual(3, try r.streamDelimiter(&w, '\n'));
+ try testing.expectEqualStrings("foo", w.buffered());
+ try testing.expectEqual(0, try r.streamDelimiter(&w, '\n'));
+ r.toss(1);
+ try testing.expectError(error.EndOfStream, r.streamDelimiter(&w, '\n'));
}
-test readDelimiterEnding {
- return error.Unimplemented;
+test streamDelimiterEnding {
+ var out_buffer: [10]u8 = undefined;
+ var r: Reader = .fixed("foo\nbars");
+ var w: Writer = .fixed(&out_buffer);
+ // Short streams are possible with this function but not with fixed.
+ try testing.expectEqual(3, try r.streamDelimiterEnding(&w, '\n'));
+ try testing.expectEqualStrings("foo", w.buffered());
+ r.toss(1);
+ try testing.expectEqual(4, try r.streamDelimiterEnding(&w, '\n'));
+ try testing.expectEqualStrings("foobars", w.buffered());
+ try testing.expectEqual(0, try r.streamDelimiterEnding(&w, '\n'));
+ try testing.expectEqual(0, try r.streamDelimiterEnding(&w, '\n'));
}
-test readDelimiterLimit {
+test streamDelimiterLimit {
return error.Unimplemented;
}