Files
c3c/lib/std/io/stream/buffer.c3
2026-02-21 21:10:08 +01:00

137 lines
3.1 KiB
Plaintext

module std::io;
struct ReadBuffer (InStream)
{
InStream wrapped_stream;
char[] bytes;
usz read_idx;
usz write_idx;
}
<*
Buffer reads from a stream.
@param [inout] self
@require bytes.len > 0
@require self.bytes.len == 0 : "Init may not run on already initialized data"
*>
fn ReadBuffer* ReadBuffer.init(&self, InStream wrapped_stream, char[] bytes)
{
*self = { .wrapped_stream = wrapped_stream, .bytes = bytes };
return self;
}
fn String ReadBuffer.str_view(&self) @inline
{
return (String)self.bytes[self.read_idx:self.write_idx - self.read_idx];
}
fn void? ReadBuffer.close(&self) @dynamic
{
if (&self.wrapped_stream.close) self.wrapped_stream.close()!;
}
fn usz? ReadBuffer.read(&self, char[] bytes) @dynamic
{
if (self.read_idx == self.write_idx)
{
if (self.read_idx == 0 && bytes.len >= self.bytes.len)
{
// Read directly into the input buffer.
return self.wrapped_stream.read(bytes)!;
}
readbuffer_refill(self)!;
}
usz n = min(self.write_idx - self.read_idx, bytes.len);
bytes[:n] = self.bytes[self.read_idx:n];
self.read_idx += n;
return n;
}
fn char? ReadBuffer.read_byte(&self) @dynamic
{
if (self.read_idx == self.write_idx) readbuffer_refill(self)!;
if (self.read_idx == self.write_idx) return io::EOF~;
char c = self.bytes[self.read_idx];
self.read_idx++;
return c;
}
fn void? readbuffer_refill(ReadBuffer* self) @local @inline
{
self.read_idx = 0;
self.write_idx = self.wrapped_stream.read(self.bytes)!;
}
struct WriteBuffer (OutStream)
{
OutStream wrapped_stream;
char[] bytes;
usz index;
}
<*
Buffer writes to a stream. Call `flush` when done writing to the buffer.
@param [inout] self
@require bytes.len > 0 : "Non-empty buffer required"
@require self.bytes.len == 0 : "Init may not run on already initialized data"
*>
fn WriteBuffer* WriteBuffer.init(&self, OutStream wrapped_stream, char[] bytes)
{
*self = { .wrapped_stream = wrapped_stream, .bytes = bytes };
return self;
}
fn String WriteBuffer.str_view(&self) @inline
{
return (String)self.bytes[:self.index];
}
fn void? WriteBuffer.close(&self) @dynamic
{
if (&self.wrapped_stream.close) return self.wrapped_stream.close();
}
fn void? WriteBuffer.flush(&self) @dynamic
{
write_buffer_write_pending(self)!;
if (&self.wrapped_stream.flush) self.wrapped_stream.flush()!;
}
fn usz? WriteBuffer.write(&self, char[] bytes) @dynamic
{
usz n = self.bytes.len - self.index;
if (bytes.len < n)
{
// Enough room in the buffer.
self.bytes[self.index:bytes.len] = bytes[..];
self.index += bytes.len;
return bytes.len;
}
write_buffer_write_pending(self)!;
if (bytes.len >= self.bytes.len)
{
// Write directly to the stream.
return self.wrapped_stream.write(bytes);
}
// Buffer the data.
self.bytes[:bytes.len] = bytes[..];
self.index = bytes.len;
return bytes.len;
}
fn void? WriteBuffer.write_byte(&self, char c) @dynamic
{
usz n = self.bytes.len - self.index;
if (n == 0)
{
write_buffer_write_pending(self)!;
}
self.bytes[self.index] = c;
self.index += 1;
}
fn void? write_buffer_write_pending(WriteBuffer* self) @local
{
self.index -= self.wrapped_stream.write(self.bytes[:self.index])!;
if (self.index != 0) return INCOMPLETE_WRITE~;
}