mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Updated stream API.
This commit is contained in:
committed by
Christoffer Lerno
parent
a6cff5c2a5
commit
9a6d83f526
@@ -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?;
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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(),
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
|
||||
@@ -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(),
|
||||
};
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user