mirror of
https://github.com/ziglang/zig.git
synced 2026-02-13 21:08:36 +00:00
std.io.Reader: fix streamDelimiter and streamDelimiterEnding
This commit is contained in:
parent
1d763c8b29
commit
77e839e283
@ -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;
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user