io::read_fully now handles unbounded streams properly

This commit is contained in:
Christoffer Lerno
2026-01-05 22:27:55 +01:00
parent d820a2356a
commit 702f836b40
4 changed files with 55 additions and 11 deletions

View File

@@ -1,7 +1,5 @@
module std::io;
import std::math;
import std::core::env;
interface InStream
{
@@ -36,7 +34,7 @@ fn usz? available(InStream s)
s.seek(curr, Seek.SET)!;
return len - curr;
}
return 0;
return ^io::UNSUPPORTED_OPERATION;
}
macro bool @is_instream(#expr) @const
@@ -90,21 +88,31 @@ macro usz? read_all(stream, char[] buffer)
}
<*
This function will read to the end of the stream.
@require @is_instream(stream)
*>
macro char[]? read_fully(Allocator allocator, stream)
{
usz len = available(stream)!;
char* data = allocator::malloc_try(allocator, len)!;
defer catch allocator::free(allocator, data);
usz read = 0;
while (read < len)
// Efficient path if it is possible to pre-allocate
if (try len = available(stream))
{
read += stream.read(data[read:len - read])!;
char* data = allocator::malloc_try(allocator, len)!;
defer catch allocator::free(allocator, data);
usz read = 0;
while (read < len)
{
read += stream.read(data[read:len - read])!;
}
return data[:len];
}
return data[:len];
ByteWriter writer;
writer.init(allocator);
copy_to(stream, &writer)!;
return writer.array_view();
}
<*
@require @is_outstream(stream)
*>

View File

@@ -43,6 +43,11 @@ fn void? ByteWriter.destroy(&self) @dynamic
*self = { };
}
fn char[] ByteWriter.array_view(self) @inline
{
return self.bytes[:self.index];
}
fn String ByteWriter.str_view(&self) @inline
{
return (String)self.bytes[:self.index];
@@ -91,7 +96,7 @@ fn usz? ByteWriter.read_from(&self, InStream reader) @dynamic
}
if (self.bytes.len == 0)
{
self.ensure_capacity(16)!;
self.ensure_capacity(256)!;
}
while (true)
{

View File

@@ -49,6 +49,7 @@
- `String.replace` no longer depends on `String.split`.
- Fix the case where `\u<unicode char>` could crash the compiler on some platforms.
- Designated initialization with ranges would not error on overflow by 1.
- `io::read_fully` now handles unbounded streams properly.
### Stdlib changes
- Add `ThreadPool` join function to wait for all threads to finish in the pool without destroying the threads.

View File

@@ -0,0 +1,30 @@
module std::io @test;
struct Test (InStream)
{
char[] data;
int index;
}
fn char? Test.read_byte(&self) @dynamic
{
if (self.index >= self.data.len) return io::EOF~;
return self.data[self.index++];
}
fn usz? Test.read(&self, char[] buffer) @dynamic
{
io::printn(*self);
if (self.index >= self.data.len) return io::EOF~;
int len = min((int)self.data.len - self.index, 16);
buffer[:len] = self.data[self.index:len];
self.index += len;
return len;
}
fn void read_fully_stream()
{
Test t = { .data = "Heokep o opewkfpewkfpoew kfopwekfop ewkf ewopfkewop fopkewfopk ewopfkewpo fkopew kfpoewk fej!" };
char[] data = io::read_fully(tmem, &t)!!;
test::eq(data, t.data);
}