Updated stream API.

This commit is contained in:
Christoffer Lerno
2023-09-02 19:48:51 +02:00
committed by Christoffer Lerno
parent a6cff5c2a5
commit 9a6d83f526
44 changed files with 837 additions and 952 deletions

View File

@@ -2,7 +2,8 @@ module std::io;
struct ReadBuffer
{
Stream stream;
inline Stream stream;
Stream* wrapped_stream;
char[] bytes;
usz read_idx;
usz write_idx;
@@ -14,19 +15,16 @@ struct ReadBuffer
* @require bytes.len > 0
* @require self.bytes.len == 0 "Init may not run on already initialized data"
**/
fn void ReadBuffer.init(&self, Stream stream, char[] bytes)
fn ReadBuffer* ReadBuffer.init(&self, Stream* wrapped_stream, char[] bytes)
{
*self = { .stream = stream, .bytes = bytes };
*self = { .stream.fns = &READBUFFER_INTERFACE, .wrapped_stream = wrapped_stream, .bytes = bytes };
return self;
}
fn Stream ReadBuffer.as_stream(&self)
{
return { .fns = &readbuffer_interface, .data = self };
}
StreamInterface readbuffer_interface = {
.read_fn = fn(s, char[] bytes) => ((ReadBuffer*)s.data).read(bytes),
.read_byte_fn = fn(s) => ((ReadBuffer*)s.data).read_byte(),
const StreamInterface READBUFFER_INTERFACE = {
.read_fn = (ReadStreamFn)&ReadBuffer.read,
.read_byte_fn = (ReadByteStreamFn)&ReadBuffer.read_byte,
};
fn String ReadBuffer.as_str(&self) @inline
@@ -41,7 +39,7 @@ fn usz! ReadBuffer.read(&self, char[] bytes)
if (self.read_idx == 0 && bytes.len >= self.bytes.len)
{
// Read directly into the input buffer.
return self.stream.read(bytes)!;
return self.wrapped_stream.read(bytes)!;
}
self.refill()!;
}
@@ -63,12 +61,13 @@ fn char! ReadBuffer.read_byte(&self)
fn void! ReadBuffer.refill(&self) @local @inline
{
self.read_idx = 0;
self.write_idx = self.stream.read(self.bytes)!;
self.write_idx = self.wrapped_stream.read(self.bytes)!;
}
struct WriteBuffer
{
Stream stream;
inline Stream stream;
Stream* wrapped_stream;
char[] bytes;
usz index;
}
@@ -79,20 +78,16 @@ struct WriteBuffer
* @require bytes.len > 0 "Non-empty buffer required"
* @require self.bytes.len == 0 "Init may not run on already initialized data"
**/
fn void WriteBuffer.init(&self, Stream stream, char[] bytes)
fn WriteBuffer* WriteBuffer.init(&self, Stream* wrapped_stream, char[] bytes)
{
*self = { .stream = stream, .bytes = bytes };
*self = { .stream.fns = &WRITEBUFFER_INTERFACE, .wrapped_stream = wrapped_stream, .bytes = bytes };
return self;
}
fn Stream WriteBuffer.as_stream(&self)
{
return { .fns = &writebuffer_interface, .data = self };
}
StreamInterface writebuffer_interface = {
.flush_fn = fn(s) => ((WriteBuffer*)s.data).flush(),
.write_fn = fn(s, char[] bytes) => ((WriteBuffer*)s.data).write(bytes),
.write_byte_fn = fn(s, char c) => ((WriteBuffer*)s.data).write_byte(c),
const StreamInterface WRITEBUFFER_INTERFACE = {
.flush_fn = (FlushStreamFn)&WriteBuffer.flush,
.write_fn = (WriteStreamFn)&WriteBuffer.write,
.write_byte_fn = (WriteByteStreamFn)&WriteBuffer.write_byte,
};
fn String WriteBuffer.as_str(&self) @inline
@@ -103,7 +98,7 @@ fn String WriteBuffer.as_str(&self) @inline
fn void! WriteBuffer.flush(&self)
{
self.write_pending()!;
if (self.stream.supports_flush()) self.stream.flush()!;
if (self.wrapped_stream.supports_flush()) self.wrapped_stream.flush()!;
}
fn usz! WriteBuffer.write(&self, char[] bytes)
@@ -120,7 +115,7 @@ fn usz! WriteBuffer.write(&self, char[] bytes)
if (bytes.len >= self.bytes.len)
{
// Write directly to the stream.
return self.stream.write(bytes);
return self.wrapped_stream.write(bytes);
}
// Buffer the data.
self.bytes[:bytes.len] = bytes[..];
@@ -138,6 +133,6 @@ fn void! WriteBuffer.write_byte(&self, char c)
fn void! WriteBuffer.write_pending(&self) @local
{
self.index -= self.stream.write(self.bytes[:self.index])!;
self.index -= self.wrapped_stream.write(self.bytes[:self.index])!;
if (self.index != 0) return IoError.INCOMPLETE_WRITE?;
}

View File

@@ -3,6 +3,7 @@ import std::math;
struct ByteBuffer
{
inline Stream stream;
Allocator* allocator;
usz max_read;
char[] bytes;
@@ -16,16 +17,17 @@ struct ByteBuffer
* max_read defines how many bytes might be kept before its internal buffer is shrinked.
* @require self.bytes.len == 0 "Buffer already initialized."
**/
fn void! ByteBuffer.init(&self, usz max_read, usz initial_capacity = 16, Allocator* using = mem::heap())
fn ByteBuffer*! ByteBuffer.init(&self, usz max_read, usz initial_capacity = 16, Allocator* using = mem::heap())
{
*self = { .allocator = using, .max_read = max_read };
*self = { .stream.fns = &BYTEBUFFER_INTERFACE, .allocator = using, .max_read = max_read };
initial_capacity = max(initial_capacity, 16);
self.grow(initial_capacity)!;
return self;
}
fn void! ByteBuffer.tinit(&self, usz max_read, usz initial_capacity = 16)
fn ByteBuffer*! ByteBuffer.tinit(&self, usz max_read, usz initial_capacity = 16)
{
self.init(max_read, initial_capacity, mem::temp())!;
return self.init(max_read, initial_capacity, mem::temp())!;
}
fn void! ByteBuffer.free(&self)
@@ -34,18 +36,13 @@ fn void! ByteBuffer.free(&self)
*self = {};
}
fn Stream ByteBuffer.as_stream(&self)
{
return { .fns = &bytebuffer_interface, .data = self };
}
StreamInterface bytebuffer_interface = {
.write_fn = fn(s, char[] bytes) => ((ByteBuffer*)s.data).write(bytes),
.write_byte_fn = fn(s, c) => ((ByteBuffer*)s.data).write_byte(c),
.read_fn = fn(s, char[] bytes) => ((ByteBuffer*)s.data).read(bytes),
.read_byte_fn = fn(s) => ((ByteBuffer*)s.data).read_byte(),
.pushback_byte_fn = fn(s) => ((ByteBuffer*)s.data).pushback_byte(),
.available_fn = fn(s) => ((ByteBuffer*)s.data).available(),
const StreamInterface BYTEBUFFER_INTERFACE = {
.write_fn = (WriteStreamFn)&ByteBuffer.write,
.write_byte_fn = (WriteByteStreamFn)&ByteBuffer.write_byte,
.read_fn = (ReadStreamFn)&ByteBuffer.read,
.read_byte_fn = (ReadByteStreamFn)&ByteBuffer.read_byte,
.pushback_byte_fn = (PushbackByteStreamFn)&ByteBuffer.pushback_byte,
.available_fn = (AvailableStreamFn)&ByteBuffer.available
};
fn usz! ByteBuffer.write(&self, char[] bytes)

View File

@@ -2,18 +2,15 @@ module std::io;
struct ByteReader
{
inline Stream stream;
char[] bytes;
usz index;
}
fn void ByteReader.init(&self, char[] bytes)
fn ByteReader* ByteReader.init(&self, char[] bytes)
{
*self = { .bytes = bytes };
}
fn Stream ByteReader.as_stream(&self)
{
return { .fns = &bytereader_interface, .data = self };
*self = { .stream = { &BYTEREADER_INTERFACE }, .bytes = bytes };
return self;
}
fn usz! ByteReader.read(&self, char[] bytes)
@@ -52,7 +49,7 @@ fn usz! ByteReader.seek(&self, isz offset, Seek seek)
return new_index;
}
fn usz! ByteReader.write_stream(&self, Stream writer)
fn usz! ByteReader.write_stream(&self, Stream* writer)
{
if (self.index >= self.bytes.len) return 0;
usz written = writer.write(self.bytes[self.index..])!;
@@ -66,14 +63,14 @@ fn usz ByteReader.available(&self) @inline
return max(0, self.bytes.len - self.index);
}
StreamInterface bytereader_interface = {
.len_fn = fn (s) => ((ByteReader*)s.data).bytes.len,
.read_fn = fn (s, char[] bytes) => ((ByteReader*)s.data).read(bytes) @inline,
.read_byte_fn = fn (s) => ((ByteReader*)s.data).read_byte() @inline,
.pushback_byte_fn = fn (s) => ((ByteReader*)s.data).pushback_byte() @inline,
.seek_fn = fn (s, offset, seek) => ((ByteReader*)s.data).seek(offset, seek) @inline,
.write_stream_fn = fn (s, writer) => ((ByteReader*)s.data).write_stream(writer) @inline,
.available_fn = fn (s) => ((ByteReader*)s.data).available() @inline,
const StreamInterface BYTEREADER_INTERFACE = {
.len_fn = fn (Stream* self) => ((ByteReader*)self).bytes.len,
.read_fn = (ReadStreamFn)&ByteReader.read,
.read_byte_fn = (ReadByteStreamFn)&ByteReader.read_byte,
.pushback_byte_fn = (PushbackByteStreamFn)&ByteReader.pushback_byte,
.seek_fn = (SeekStreamFn)&ByteReader.seek,
.write_stream_fn = (WriteToStreamFn)&ByteReader.write_stream,
.available_fn = fn (Stream* self) => ((ByteReader*)self).available(),
};

View File

@@ -2,6 +2,7 @@ module std::io;
struct ByteWriter
{
inline Stream stream;
char[] bytes;
usz index;
Allocator* allocator;
@@ -11,30 +12,27 @@ struct ByteWriter
* @param [&inout] self
* @param [&in] using
* @require self.bytes.len == 0 "Init may not run on on already initialized data"
* @ensure using != null, index == 0
* @ensure using != null, self.index == 0
**/
fn void ByteWriter.init(&self, Allocator* using = mem::heap())
fn ByteWriter* ByteWriter.init(&self, Allocator* using = mem::heap())
{
*self = { .bytes = {}, .allocator = using };
*self = { .stream.fns = &BYTEWRITER_INTERFACE, .bytes = {}, .allocator = using };
return self;
}
fn void ByteWriter.init_buffer(&self, char[] data)
fn ByteWriter* ByteWriter.init_buffer(&self, char[] data)
{
*self = { .bytes = data, .allocator = null };
*self = { .stream.fns = &BYTEWRITER_INTERFACE, .bytes = data, .allocator = null };
return self;
}
/**
* @param [&inout] self
* @require self.bytes.len == 0 "Init may not run on on already initialized data"
**/
fn void ByteWriter.tinit(&self)
fn ByteWriter* ByteWriter.tinit(&self)
{
*self = { .bytes = {}, .allocator = mem::temp() };
}
fn Stream ByteWriter.as_stream(&self)
{
return { .fns = &bytewriter_interface, .data = self };
return self.init(mem::temp());
}
fn void ByteWriter.destroy(&self)
@@ -77,7 +75,7 @@ fn void! ByteWriter.write_byte(&self, char c)
* @param [&inout] self
* @param reader
**/
fn usz! ByteWriter.read_from(&self, Stream reader)
fn usz! ByteWriter.read_from(&self, Stream* reader)
{
usz start_index = self.index;
if (reader.supports_available())
@@ -113,10 +111,10 @@ fn usz! ByteWriter.read_from(&self, Stream reader)
}
}
StreamInterface bytewriter_interface = {
.destroy_fn = fn (s) => ((ByteWriter*)s.data).destroy(),
.len_fn = fn (s) => ((ByteWriter*)s.data).bytes.len,
.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),
const StreamInterface BYTEWRITER_INTERFACE = {
.destroy_fn = fn (s) => ((ByteWriter*)s).destroy(),
.len_fn = fn (s) => ((ByteWriter*)s).bytes.len,
.write_fn = (WriteStreamFn)&ByteWriter.write,
.write_byte_fn = (WriteByteStreamFn)&ByteWriter.write_byte,
.read_stream_fn = (ReadFromStreamFn)&ByteWriter.read_from,
};

View File

@@ -1,14 +1,38 @@
module std::io;
fn Stream DString.as_stream(&self)
struct DStringStream
{
return { .fns = &dstring_interface, .data = self };
inline Stream stream;
DString* wrapped_string;
}
StreamInterface dstring_interface = {
.destroy_fn = fn (s) => ((DString*)s.data).free(),
.len_fn = fn (s) => ((DString*)s.data).len(),
.write_fn = fn (s, char[] bytes) { ((DString*)s.data).append_chars((String)bytes); return bytes.len; },
.write_byte_fn = fn (s, char c) => ((DString*)s.data).append_char(c),
.read_stream_fn = fn (s, reader) => ((DString*)s.data).read_from_stream(reader),
fn DStringStream* DStringStream.init(&self, DString* wrapped_string)
{
*self = { .stream.fns = &DSTRINGSTREAM_INTERFACE, .wrapped_string = wrapped_string };
return self;
}
fn usz DStringStream.len(&self) => self.wrapped_string.len();
fn usz! DStringStream.write(&self, char[] bytes)
{
self.wrapped_string.append_chars((String)bytes);
return bytes.len;
}
fn void! DStringStream.write_byte(&self, char c)
{
self.wrapped_string.append_char(c);
}
fn usz! DStringStream.read_from_stream(&self, Stream* reader)
{
return self.wrapped_string.read_from_stream(reader);
}
const StreamInterface DSTRINGSTREAM_INTERFACE = {
.len_fn = (LenStreamFn)&DStringStream.len,
.write_fn = (WriteStreamFn)&DStringStream.write,
.write_byte_fn = (WriteByteStreamFn)&DStringStream.write_byte,
.read_stream_fn = (ReadFromStreamFn)&DStringStream.read_from_stream,
};

View File

@@ -1,18 +0,0 @@
module std::io;
fn Stream File.as_stream(&self)
{
return { .fns = &filestream_interface, .data = self };
}
StreamInterface filestream_interface = {
.close_fn = fn (s) => ((File*)s.data).close(),
.seek_fn = fn (s, offset, seek) => ((File*)s.data).seek(offset, seek) @inline,
.read_fn = fn (s, char[] bytes) => ((File*)s.data).read(bytes) @inline,
.write_fn = fn (s, char[] bytes) => ((File*)s.data).write(bytes) @inline,
.write_byte_fn = fn (s, char c) => ((File*)s.data).putc(c) @inline,
.read_byte_fn = fn (s) => ((File*)s.data).getc() @inline,
.flush_fn = fn (s) => ((File*)s.data).flush() @inline,
};

View File

@@ -2,27 +2,35 @@ module std::io::stream;
struct LimitReader
{
Stream reader;
inline Stream stream;
Stream* wrapped_stream;
usz limit;
}
fn void LimitReader.init(&self, Stream reader, usz limit)
/**
* @param [&inout] wrapped_stream "The stream to read from"
* @param limit "The max limit to read"
**/
fn LimitReader* LimitReader.init(&self, Stream* wrapped_stream, usz limit)
{
*self = { .reader = reader, .limit = limit };
*self = { .stream.fns = &LIMITREADER_INTERFACE, .wrapped_stream = wrapped_stream, .limit = limit };
return self;
}
fn usz! LimitReader.read(&self, char[] bytes)
{
if (self.limit == 0) return IoError.EOF?;
usz m = min(bytes.len, self.limit);
usz n = self.reader.read(bytes[:m])!;
usz n = self.wrapped_stream.read(bytes[:m])!;
self.limit -= n;
return n;
}
fn Stream LimitReader.as_stream(&self)
fn char! LimitReader.read_byte(&self)
{
return { .fns = &limitreader_interface, .data = self };
if (self.limit == 0) return IoError.EOF?;
defer try self.limit--;
return self.wrapped_stream.read_byte();
}
fn usz LimitReader.available(&self) @inline
@@ -30,7 +38,8 @@ fn usz LimitReader.available(&self) @inline
return self.limit;
}
StreamInterface limitreader_interface = {
.read_fn = fn(s, char[] bytes) => ((LimitReader*)s.data).read(bytes),
.available_fn = fn(s) => ((LimitReader*)s.data).available(),
const StreamInterface LIMITREADER_INTERFACE = {
.read_fn = (ReadStreamFn)&LimitReader.read,
.read_byte_fn = (ReadByteStreamFn)&LimitReader.read_byte,
.available_fn = fn(s) => ((LimitReader*)s).available(),
};

View File

@@ -2,7 +2,7 @@ module std::io;
struct Scanner
{
Stream reader;
Stream* stream;
char[] buf;
usz pattern_idx;
usz read_idx;
@@ -12,11 +12,15 @@ struct Scanner
* Scanner provides a way to read delimited data (with newlines as the default).
* The supplied buffer must be at least as large as the expected data length
* including its pattern.
*
* @param [&in] stream "The stream to read data from."
* @require buffer.len > 0 "Non-empty buffer required."
* @require stream.supports_read() "The stream must support read."
*
**/
fn void Scanner.init(&self, Stream reader, char[] buffer)
fn void Scanner.init(&self, Stream* stream, char[] buffer)
{
*self = { .reader = reader, .buf = buffer };
*self = { .stream = stream, .buf = buffer };
}
/**
@@ -81,7 +85,7 @@ macro usz! Scanner.find(&self, buf, pattern) @private
macro usz! Scanner.refill(&self, buf) @private
{
usz! n = self.reader.read(buf);
usz! n = self.stream.read(buf);
if (catch err = n)
{
case IoError.EOF: