Files
c3c/lib/std/io/stream/multireader.c3
konimarti f3304acc93 Add io stream primitives (#1626)
* io: implement MultiReader struct

Implement a MultiReader (InStream) which sequentially read from the
provided readers (InStreams). Return IoError.EOF when all of the readers
are read.

* io: implement MultiWriter struct

Implement a MultiWriter (OutStream). The MultiWriter duplicates its
writes to all the provided writers (OutStream).

* io: implement TeeReader struct

Implement a TeeReader (InStream) which reads from a wrapped reader
(InStream) and writes data to the provided writer (OutStream).
2024-11-15 23:18:29 +01:00

71 lines
1.5 KiB
Plaintext

module std::io;
/* MultiReader implements the InStream interface and provides a logical
* concatenation of the provided readers. They are read sequentially. If all the
* data has been read, IoError.EOF is returned.
*/
struct MultiReader (InStream)
{
InStream[] readers;
usz index;
Allocator allocator;
}
<*
@param [&inout] self
@param [&inout] allocator
@require self.readers.len == 0 "Init may not run on already initialized data"
@ensure self.index == 0
*>
fn MultiReader* MultiReader.new_init(&self, InStream... readers, Allocator allocator = allocator::heap())
{
InStream []copy = allocator::new_array(allocator, InStream, readers.len);
copy[..] = readers[..];
*self = { .readers = copy, .allocator = allocator };
return self;
}
<*
@param [&inout] self
@require self.readers.len == 0 "Init may not run on already initialized data"
@ensure self.index == 0
*>
fn MultiReader* MultiReader.temp_init(&self, InStream... readers)
{
return self.new_init(...readers, allocator: allocator::temp());
}
fn void MultiReader.free(&self)
{
if (!self.allocator) return;
allocator::free(self.allocator, self.readers);
*self = {};
}
fn usz! MultiReader.read(&self, char[] bytes) @dynamic
{
InStream r = self.readers[self.index];
usz! n = r.read(bytes);
if (catch err = n)
{
case IoError.EOF:
self.index++;
if (self.index >= self.readers.len)
{
return IoError.EOF?;
}
return self.read(bytes);
default:
return err?;
}
return n;
}
fn char! MultiReader.read_byte(&self) @dynamic
{
char[1] data;
self.read(data[..])!;
return data[0];
}