mirror of
https://github.com/ziglang/zig.git
synced 2026-02-12 20:37:54 +00:00
std.io.Reader: fix fill implementation
now it avoids writing to buffer in the case of fixed
This commit is contained in:
parent
1e1f026c83
commit
d03d273117
@ -106,7 +106,7 @@ const ending_state: Reader = .fixed(&.{});
|
||||
pub const ending: *Reader = @constCast(&ending_state);
|
||||
|
||||
pub fn limited(r: *Reader, limit: Limit, buffer: []u8) Limited {
|
||||
return Limited.init(r, limit, buffer);
|
||||
return .init(r, limit, buffer);
|
||||
}
|
||||
|
||||
/// Constructs a `Reader` such that it will read from `buffer` and then end.
|
||||
@ -921,21 +921,70 @@ pub fn streamDelimiterLimit(
|
||||
/// Reads from the stream until specified byte is found, discarding all data,
|
||||
/// including the delimiter.
|
||||
///
|
||||
/// If end of stream is found, this function succeeds.
|
||||
pub fn discardDelimiterInclusive(r: *Reader, delimiter: u8) Error!void {
|
||||
_ = r;
|
||||
_ = delimiter;
|
||||
@panic("TODO");
|
||||
/// Returns number of bytes discarded, or `error.EndOfStream` if the delimiter
|
||||
/// is not found.
|
||||
///
|
||||
/// See also:
|
||||
/// * `discardDelimiterExclusive`
|
||||
/// * `discardDelimiterLimit`
|
||||
pub fn discardDelimiterInclusive(r: *Reader, delimiter: u8) Error!usize {
|
||||
const n = discardDelimiterLimit(r, delimiter, .unlimited) catch |err| switch (err) {
|
||||
error.StreamTooLong => unreachable, // unlimited is passed
|
||||
else => |e| return e,
|
||||
};
|
||||
if (r.seek == r.end) return error.EndOfStream;
|
||||
assert(r.buffer[r.seek] == delimiter);
|
||||
toss(r, 1);
|
||||
return n + 1;
|
||||
}
|
||||
|
||||
/// Reads from the stream until specified byte is found, discarding all data,
|
||||
/// excluding the delimiter.
|
||||
///
|
||||
/// Succeeds if stream ends before delimiter found.
|
||||
pub fn discardDelimiterExclusive(r: *Reader, delimiter: u8) ShortError!void {
|
||||
_ = r;
|
||||
_ = delimiter;
|
||||
@panic("TODO");
|
||||
/// Returns the number of bytes discarded.
|
||||
///
|
||||
/// Succeeds if stream ends before delimiter found. End of stream can be
|
||||
/// detected by checking if the delimiter is buffered.
|
||||
///
|
||||
/// See also:
|
||||
/// * `discardDelimiterInclusive`
|
||||
/// * `discardDelimiterLimit`
|
||||
pub fn discardDelimiterExclusive(r: *Reader, delimiter: u8) ShortError!usize {
|
||||
return discardDelimiterLimit(r, delimiter, .unlimited) catch |err| switch (err) {
|
||||
error.StreamTooLong => unreachable, // unlimited is passed
|
||||
else => |e| return e,
|
||||
};
|
||||
}
|
||||
|
||||
pub const DiscardDelimiterLimitError = error{
|
||||
ReadFailed,
|
||||
/// The delimiter was not found within the limit.
|
||||
StreamTooLong,
|
||||
};
|
||||
|
||||
/// Reads from the stream until specified byte is found, discarding all data,
|
||||
/// excluding the delimiter.
|
||||
///
|
||||
/// Returns the number of bytes discarded.
|
||||
///
|
||||
/// Succeeds if stream ends before delimiter found. End of stream can be
|
||||
/// detected by checking if the delimiter is buffered.
|
||||
pub fn discardDelimiterLimit(r: *Reader, delimiter: u8, limit: Limit) DiscardDelimiterLimitError!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 (std.mem.indexOfScalar(u8, available, delimiter)) |delimiter_index| {
|
||||
r.toss(delimiter_index);
|
||||
remaining -= delimiter_index;
|
||||
return @intFromEnum(limit) - remaining;
|
||||
}
|
||||
r.toss(available.len);
|
||||
remaining -= available.len;
|
||||
}
|
||||
return error.StreamTooLong;
|
||||
}
|
||||
|
||||
/// Fills the buffer such that it contains at least `n` bytes, without
|
||||
@ -951,6 +1000,19 @@ pub fn fill(r: *Reader, n: usize) Error!void {
|
||||
@branchHint(.likely);
|
||||
return;
|
||||
}
|
||||
if (r.seek + n <= r.buffer.len) while (true) {
|
||||
const end_cap = r.buffer[r.end..];
|
||||
var writer: Writer = .fixed(end_cap);
|
||||
r.end += r.vtable.stream(r, &writer, .limited(end_cap.len)) catch |err| switch (err) {
|
||||
error.WriteFailed => unreachable,
|
||||
else => |e| return e,
|
||||
};
|
||||
if (r.seek + n <= r.end) return;
|
||||
};
|
||||
if (r.vtable.stream == &endingStream) {
|
||||
// Protect the `@constCast` of `fixed`.
|
||||
return error.EndOfStream;
|
||||
}
|
||||
rebaseCapacity(r, n);
|
||||
var writer: Writer = .{
|
||||
.buffer = r.buffer,
|
||||
@ -1371,37 +1433,65 @@ test streamDelimiterLimit {
|
||||
var w: Writer = .fixed(&out_buffer);
|
||||
try testing.expectError(error.StreamTooLong, r.streamDelimiterLimit(&w, '\n', .limited(2)));
|
||||
try testing.expectEqual(1, try r.streamDelimiterLimit(&w, '\n', .limited(3)));
|
||||
r.toss(1);
|
||||
try testing.expectEqualStrings("\n", try r.take(1));
|
||||
try testing.expectEqual(4, try r.streamDelimiterLimit(&w, '\n', .unlimited));
|
||||
try testing.expectEqualStrings("foobars", w.buffered());
|
||||
}
|
||||
|
||||
test discardDelimiterExclusive {
|
||||
return error.Unimplemented;
|
||||
var r: Reader = .fixed("foob\nar");
|
||||
try testing.expectEqual(4, try r.discardDelimiterExclusive('\n'));
|
||||
try testing.expectEqualStrings("\n", try r.take(1));
|
||||
try testing.expectEqual(2, try r.discardDelimiterExclusive('\n'));
|
||||
try testing.expectEqual(0, try r.discardDelimiterExclusive('\n'));
|
||||
}
|
||||
|
||||
test discardDelimiterInclusive {
|
||||
return error.Unimplemented;
|
||||
var r: Reader = .fixed("foob\nar");
|
||||
try testing.expectEqual(5, try r.discardDelimiterInclusive('\n'));
|
||||
try testing.expectError(error.EndOfStream, r.discardDelimiterInclusive('\n'));
|
||||
}
|
||||
|
||||
test discardDelimiterLimit {
|
||||
var r: Reader = .fixed("foob\nar");
|
||||
try testing.expectError(error.StreamTooLong, r.discardDelimiterLimit('\n', .limited(4)));
|
||||
try testing.expectEqual(0, try r.discardDelimiterLimit('\n', .limited(2)));
|
||||
try testing.expectEqualStrings("\n", try r.take(1));
|
||||
try testing.expectEqual(2, try r.discardDelimiterLimit('\n', .unlimited));
|
||||
try testing.expectEqual(0, try r.discardDelimiterLimit('\n', .unlimited));
|
||||
}
|
||||
|
||||
test fill {
|
||||
return error.Unimplemented;
|
||||
var r: Reader = .fixed("abc");
|
||||
try r.fill(1);
|
||||
try r.fill(3);
|
||||
}
|
||||
|
||||
test takeByte {
|
||||
return error.Unimplemented;
|
||||
var r: Reader = .fixed("ab");
|
||||
try testing.expectEqual('a', try r.takeByte());
|
||||
try testing.expectEqual('b', try r.takeByte());
|
||||
try testing.expectError(error.EndOfStream, r.takeByte());
|
||||
}
|
||||
|
||||
test takeByteSigned {
|
||||
return error.Unimplemented;
|
||||
var r: Reader = .fixed(&.{ 255, 5 });
|
||||
try testing.expectEqual(-1, try r.takeByteSigned());
|
||||
try testing.expectEqual(5, try r.takeByteSigned());
|
||||
try testing.expectError(error.EndOfStream, r.takeByteSigned());
|
||||
}
|
||||
|
||||
test takeInt {
|
||||
return error.Unimplemented;
|
||||
var r: Reader = .fixed(&.{ 0x12, 0x34, 0x56 });
|
||||
try testing.expectEqual(0x1234, try r.takeInt(u16, .big));
|
||||
try testing.expectError(error.EndOfStream, r.takeInt(u16, .little));
|
||||
}
|
||||
|
||||
test takeVarInt {
|
||||
return error.Unimplemented;
|
||||
var r: Reader = .fixed(&.{ 0x12, 0x34, 0x56 });
|
||||
std.debug.print("{x}", .{r.buffer});
|
||||
try testing.expectEqual(0x123456, try r.takeVarInt(u64, .big, 3));
|
||||
try testing.expectError(error.EndOfStream, r.takeVarInt(u16, .little, 1));
|
||||
}
|
||||
|
||||
test takeStruct {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user