lib/std: fix ByteWriter.read_from method (#793)

* lib/std: fix ByteWriter.read_from method

When reading from a stream which does not have an available method,
ByteWriter would not make any progress if its buffer was empty.

Signed-off-by: Pierre Curto <pierre.curto@gmail.com>

* test/unit/stdlib/io: use separate module for TestReader

Signed-off-by: Pierre Curto <pierre.curto@gmail.com>

---------

Signed-off-by: Pierre Curto <pierre.curto@gmail.com>
This commit is contained in:
Pierre Curto
2023-06-23 10:44:36 +02:00
committed by GitHub
parent c46017f0dc
commit 0ab0f727ad
2 changed files with 52 additions and 8 deletions

View File

@@ -79,19 +79,21 @@ fn void! ByteWriter.write_byte(ByteWriter* writer, char c)
**/
fn usz! ByteWriter.read_from(ByteWriter* writer, Stream* reader)
{
usz start_index = writer.index;
if (reader.supports_available())
{
usz total_read = 0;
while (usz available = reader.available()!)
{
writer.ensure_capacity(writer.index + available)!;
usz len = reader.read(writer.bytes[writer.index..])!;
total_read += len;
writer.index += len;
usz read = reader.read(writer.bytes[writer.index..])!;
writer.index += read;
}
return total_read;
return writer.index - start_index;
}
if (writer.bytes.len == 0)
{
writer.ensure_capacity(16)!;
}
usz total_read = 0;
while (true)
{
// See how much we can read.
@@ -100,12 +102,13 @@ fn usz! ByteWriter.read_from(ByteWriter* writer, Stream* reader)
if (len_to_read < 16)
{
writer.ensure_capacity(writer.bytes.len * 2)!;
len_to_read = writer.bytes.len - writer.index;
}
// Read into the rest of the buffer
usz read = reader.read(writer.bytes[writer.index..])!;
writer.index += read;
// Ok, we reached the end.
if (read < len_to_read) return total_read;
if (read < len_to_read) return writer.index - start_index;
// Otherwise go another round
}
}
@@ -116,4 +119,4 @@ StreamInterface bytewriter_interface = {
.write_fn = fn (s, char[] bytes) => ((ByteWriter*)s.data).write(bytes),
.write_byte_fn = fn (s, char c) => ((ByteWriter*)s.data).write_byte(c),
.read_stream_fn = fn (s, reader) => ((ByteWriter*)s.data).read_from(reader),
};
};

View File

@@ -35,3 +35,44 @@ fn void! bytewriter_buffer()
assert(o == "hello");
assert(@catchof(s.write("xxxx")));
}
fn void! bytewriter_read_from()
{
char[] data = "Lorem ipsum dolor sit amet biam.";
TestReader r = { .bytes = data };
Stream s = r.as_stream();
ByteWriter bw;
bw.tinit();
bw.read_from(&s)!;
assert(bw.as_str() == data);
}
module std::io;
// TestReader only has the read method to trigger the path
// in ByteWriter.read_from that does not rely on the available method.
struct TestReader
{
char[] bytes;
usz index;
}
fn Stream TestReader.as_stream(TestReader *r)
{
return { .fns = &testReader_interface, .data = r };
}
fn usz! TestReader.read(TestReader *r, char[] bytes)
{
usz left = r.bytes.len - r.index;
if (left == 0) return 0;
usz n = min(left, bytes.len);
mem::copy(bytes.ptr, &r.bytes[r.index], n);
r.index += n;
return n;
}
StreamInterface testReader_interface = {
.read_fn = fn(s, char[] bytes) => ((TestReader*)s.data).read(bytes),
};