mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Interface based streams. Fix for initializing with a force unwrap inside. Allow $define to take a list. Allow $define to return error on argument type mismatch in call. Fixed broken bit operations on boolean vectors.
This commit is contained in:
committed by
Christoffer Lerno
parent
e4c1328ef2
commit
1aa038c92f
@@ -202,21 +202,21 @@ fn void*! TempAllocator.acquire(&self, usz size, bool clear, usz alignment, usz
|
||||
return &page.data[0];
|
||||
}
|
||||
|
||||
fn void TempAllocator.print_pages(&self, File f)
|
||||
fn void! TempAllocator.print_pages(&self, File f)
|
||||
{
|
||||
TempAllocatorPage *last_page = self.last_page;
|
||||
if (!last_page)
|
||||
{
|
||||
f.printf("No pages.\n");
|
||||
io::fprintf(&f, "No pages.\n")!;
|
||||
return;
|
||||
}
|
||||
f.printf("---Pages----\n");
|
||||
io::fprintf(&f, "---Pages----\n")!;
|
||||
uint index = 0;
|
||||
while (last_page)
|
||||
{
|
||||
bool is_not_aligned = !(last_page.size & (1u64 << 63));
|
||||
f.printf("%d. Alloc: %d %d at %p%s\n", ++index,
|
||||
last_page.size & ~(1u64 << 63), last_page.mark, &last_page.data[0], is_not_aligned ? "" : " [aligned]");
|
||||
io::fprintf(&f, "%d. Alloc: %d %d at %p%s\n", ++index,
|
||||
last_page.size & ~(1u64 << 63), last_page.mark, &last_page.data[0], is_not_aligned ? "" : " [aligned]")!;
|
||||
last_page = last_page.prev_page;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,33 +94,33 @@ fn bool print_backtrace(String message, int backtraces_to_ignore) @if(env::DARWI
|
||||
BacktraceList! backtrace = darwin::backtrace_load(mem::temp());
|
||||
if (catch backtrace) return false;
|
||||
if (backtrace.len() <= backtraces_to_ignore) return false;
|
||||
(void)io::stderr().print("\nERROR: '");
|
||||
(void)io::stderr().print(message);
|
||||
io::printn("'");
|
||||
io::eprint("\nERROR: '");
|
||||
io::eprint(message);
|
||||
io::eprintn("'");
|
||||
foreach (i, &trace : backtrace)
|
||||
{
|
||||
if (i < backtraces_to_ignore) continue;
|
||||
if (trace.is_unknown())
|
||||
{
|
||||
(void)io::stderr().printn(" in ???");
|
||||
io::eprintn(" in ???");
|
||||
continue;
|
||||
}
|
||||
if (trace.has_file())
|
||||
{
|
||||
(void)io::stderr().printfn(" in %s (%s:%d) [%s]", trace.function, trace.file, trace.line, trace.object_file);
|
||||
io::eprintfn(" in %s (%s:%d) [%s]", trace.function, trace.file, trace.line, trace.object_file);
|
||||
continue;
|
||||
}
|
||||
(void)io::stderr().printfn(" in %s (source unavailable) [%s]", trace.function, trace.object_file);
|
||||
io::eprintfn(" in %s (source unavailable) [%s]", trace.function, trace.object_file);
|
||||
}
|
||||
return true;
|
||||
};
|
||||
}
|
||||
fn void default_panic(String message, String file, String function, uint line) @if(env::DARWIN)
|
||||
{
|
||||
$if $defined(io::stderr) && $defined(Stream.printf):
|
||||
$if $defined(io::stderr):
|
||||
if (!print_backtrace(message, 2))
|
||||
{
|
||||
(void)io::stderr().printfn("\nERROR: '%s', in %s (%s:%d)", message, function, file, line);
|
||||
io::eprintfn("\nERROR: '%s', in %s (%s:%d)", message, function, file, line);
|
||||
return;
|
||||
}
|
||||
$endif
|
||||
@@ -130,23 +130,23 @@ fn void default_panic(String message, String file, String function, uint line) @
|
||||
fn void default_panic(String message, String file, String function, uint line) @if(!env::DARWIN)
|
||||
{
|
||||
CallstackElement* stack = $$stacktrace();
|
||||
$if $defined(io::stderr) && $defined(Stream.printf):
|
||||
$if $defined(io::stderr):
|
||||
if (stack) stack = stack.prev;
|
||||
if (stack)
|
||||
{
|
||||
(void)io::stderr().print("\nERROR: '");
|
||||
(void)io::stderr().print(message);
|
||||
(void)io::stderr().printn("'");
|
||||
io::eprint("\nERROR: '");
|
||||
io::eprint(message);
|
||||
io::eprintn("'");
|
||||
}
|
||||
else
|
||||
{
|
||||
(void)io::stderr().print("\nERROR: '");
|
||||
(void)io::stderr().print(message);
|
||||
(void)io::stderr().printfn("', in %s (%s:%d)", function, file, line);
|
||||
io::eprint("\nERROR: '");
|
||||
io::eprint(message);
|
||||
io::eprintfn("', in %s (%s:%d)", function, file, line);
|
||||
}
|
||||
while (stack)
|
||||
{
|
||||
(void)io::stderr().printfn(" in %s %s (%s:%d)", stack.location.name, stack.function, stack.file, stack.line);
|
||||
io::eprintfn(" in %s %s (%s:%d)", stack.location.name, stack.function, stack.file, stack.line);
|
||||
if (stack == stack.prev) break;
|
||||
stack = stack.prev;
|
||||
}
|
||||
@@ -398,10 +398,10 @@ fn void sig_bus_error(CInt i)
|
||||
$if !env::DARWIN:
|
||||
sig_panic("Illegal memory access.");
|
||||
$else
|
||||
$if $defined(io::stderr) && $defined(Stream.printf):
|
||||
$if $defined(io::stderr):
|
||||
if (!print_backtrace("Illegal memory access.", 1))
|
||||
{
|
||||
(void)io::stderr().printn("\nERROR: 'Illegal memory access'.");
|
||||
io::eprintn("\nERROR: 'Illegal memory access'.");
|
||||
}
|
||||
$endif
|
||||
$endif
|
||||
@@ -413,10 +413,10 @@ fn void sig_segmentation_fault(CInt i)
|
||||
$if !env::DARWIN:
|
||||
sig_panic("Out of bounds memory access.");
|
||||
$else
|
||||
$if $defined(io::stderr) && $defined(Stream.printf):
|
||||
$if $defined(io::stderr):
|
||||
if (!print_backtrace("Out of bounds memory access.", 1))
|
||||
{
|
||||
(void)io::stderr().printn("\nERROR: Memory error without backtrace, possible stack overflow.");
|
||||
io::eprintn("\nERROR: Memory error without backtrace, possible stack overflow.");
|
||||
}
|
||||
$endif
|
||||
$endif
|
||||
|
||||
@@ -83,9 +83,9 @@ macro greater_eq(a, b) @builtin
|
||||
macro bool equals(a, b) @builtin
|
||||
{
|
||||
$switch
|
||||
$case $defined(a.equals):
|
||||
$case $defined(a.equals, a.equals(b)):
|
||||
return a.equals(b);
|
||||
$case $defined(a.compare_to):
|
||||
$case $defined(a.compare_to, a.compare_to(b)):
|
||||
return a.compare_to(b) == 0;
|
||||
$case $defined(a.less):
|
||||
return !a.less(b) && !b.less(a);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
module std::core::dstring;
|
||||
import std::io;
|
||||
|
||||
distinct DString = void*;
|
||||
distinct DString (OutStream) = void*;
|
||||
|
||||
const usz MIN_CAPACITY @private = 16;
|
||||
|
||||
@@ -79,9 +80,9 @@ fn usz DString.capacity(self)
|
||||
return self.data().capacity;
|
||||
}
|
||||
|
||||
fn usz DString.len(self)
|
||||
fn usz DString.len(&self) @dynamic
|
||||
{
|
||||
if (!self) return 0;
|
||||
if (!*self) return 0;
|
||||
return self.data().len;
|
||||
}
|
||||
|
||||
@@ -255,6 +256,17 @@ fn void DString.clear(self)
|
||||
self.data().len = 0;
|
||||
}
|
||||
|
||||
fn usz! DString.write(&self, char[] buffer) @dynamic
|
||||
{
|
||||
self.append_chars((String)buffer);
|
||||
return buffer.len;
|
||||
}
|
||||
|
||||
fn void! DString.write_byte(&self, char c) @dynamic
|
||||
{
|
||||
self.append_char(c);
|
||||
}
|
||||
|
||||
fn void DString.append_char(&self, char c)
|
||||
{
|
||||
if (!*self)
|
||||
@@ -387,9 +399,9 @@ fn void DString.reserve(&self, usz addition)
|
||||
*self = (DString)realloc(data, StringData.sizeof + new_capacity, .using = data.allocator);
|
||||
}
|
||||
|
||||
fn usz! DString.read_from_stream(&self, Stream* reader)
|
||||
fn usz! DString.read_from_stream(&self, InStream* reader)
|
||||
{
|
||||
if (reader.supports_available())
|
||||
if (&reader.available)
|
||||
{
|
||||
usz total_read = 0;
|
||||
while (usz available = reader.available()!)
|
||||
|
||||
@@ -3,11 +3,11 @@ import std::io;
|
||||
|
||||
struct CsvReader
|
||||
{
|
||||
Stream* stream;
|
||||
InStream* stream;
|
||||
String separator;
|
||||
}
|
||||
|
||||
fn void CsvReader.init(&self, Stream* stream, String separator = ",")
|
||||
fn void CsvReader.init(&self, InStream* stream, String separator = ",")
|
||||
{
|
||||
self.stream = stream;
|
||||
self.separator = separator;
|
||||
@@ -15,9 +15,9 @@ fn void CsvReader.init(&self, Stream* stream, String separator = ",")
|
||||
|
||||
fn String[]! CsvReader.read_row(self, Allocator* using = mem::heap())
|
||||
{
|
||||
@pool()
|
||||
@pool(using)
|
||||
{
|
||||
return self.stream.treadline().split(self.separator, .using = using);
|
||||
return io::treadline(self.stream).split(self.separator, .using = using);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -30,13 +30,13 @@ fn void! CsvReader.skip_row(self) @maydiscard
|
||||
{
|
||||
@pool()
|
||||
{
|
||||
self.stream.readline(mem::temp())!;
|
||||
(void)io::treadline(self.stream);
|
||||
};
|
||||
}
|
||||
|
||||
macro CsvReader.@each_row(self, int rows = int.max; @body(String[] row))
|
||||
{
|
||||
Stream* stream = self.stream;
|
||||
InputStream* stream = self.stream;
|
||||
String sep = self.separator;
|
||||
while (rows--)
|
||||
{
|
||||
|
||||
@@ -15,7 +15,7 @@ fault JsonParsingError
|
||||
INVALID_NUMBER,
|
||||
}
|
||||
|
||||
fn Object*! parse(Stream* s, Allocator* using = mem::heap())
|
||||
fn Object*! parse(InStream* s, Allocator* using = mem::heap())
|
||||
{
|
||||
JsonContext context = { .last_string = dstring::new_with_capacity(64, using), .stream = s, .allocator = using };
|
||||
defer context.last_string.free();
|
||||
@@ -44,7 +44,7 @@ enum JsonTokenType @local
|
||||
struct JsonContext @local
|
||||
{
|
||||
uint line;
|
||||
Stream* stream;
|
||||
InStream* stream;
|
||||
Allocator* allocator;
|
||||
JsonTokenType token;
|
||||
DString last_string;
|
||||
|
||||
@@ -2,15 +2,12 @@ module std::io;
|
||||
|
||||
struct BitReader
|
||||
{
|
||||
Stream reader;
|
||||
InStream* reader;
|
||||
uint bits;
|
||||
uint len;
|
||||
}
|
||||
|
||||
/**
|
||||
* @require byte_reader.supports_read_byte()
|
||||
**/
|
||||
fn void BitReader.init(&self, Stream byte_reader)
|
||||
fn void BitReader.init(&self, InStream* byte_reader)
|
||||
{
|
||||
*self = { .reader = byte_reader };
|
||||
}
|
||||
@@ -43,15 +40,12 @@ fn char! BitReader.read_bits(&self, uint nbits)
|
||||
|
||||
struct BitWriter
|
||||
{
|
||||
Stream writer;
|
||||
OutStream* writer;
|
||||
uint bits;
|
||||
uint len;
|
||||
}
|
||||
|
||||
/**
|
||||
* @require byte_writer.supports_write_byte()
|
||||
**/
|
||||
fn void BitWriter.init(&self, Stream byte_writer)
|
||||
fn void BitWriter.init(&self, OutStream* byte_writer)
|
||||
{
|
||||
*self = { .writer = byte_writer };
|
||||
}
|
||||
@@ -63,7 +57,7 @@ fn void! BitWriter.flush(&self)
|
||||
uint n = (self.len + 7) / 8;
|
||||
char[4] buffer;
|
||||
bitorder::write(bits, &buffer, UIntBE);
|
||||
self.writer.write_all(buffer[:n])!;
|
||||
io::write_all(self.writer, buffer[:n])!;
|
||||
self.len = 0;
|
||||
}
|
||||
|
||||
@@ -83,7 +77,7 @@ fn void! BitWriter.write_bits(&self, uint bits, uint nbits)
|
||||
lbits |= (ulong)(bits >> left) << (64 - (n - left));
|
||||
char[8] buffer;
|
||||
bitorder::write(lbits, &buffer, ULongBE);
|
||||
self.writer.write_all(buffer[:to_write])!;
|
||||
io::write_all(self.writer, buffer[:to_write])!;
|
||||
}
|
||||
self.bits <<= left;
|
||||
self.bits |= bits & ((1 << left) - 1);
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
module std::io;
|
||||
import libc;
|
||||
|
||||
struct File
|
||||
struct File (InStream, OutStream)
|
||||
{
|
||||
inline Stream stream;
|
||||
CFile file;
|
||||
}
|
||||
|
||||
@@ -22,7 +21,7 @@ fn File! open_path(Path path, String mode)
|
||||
|
||||
fn File from_handle(CFile file)
|
||||
{
|
||||
return { .stream.fns = &FILESTREAM_INTERFACE, .file = file };
|
||||
return { .file = file };
|
||||
}
|
||||
|
||||
fn bool is_file(String path)
|
||||
@@ -49,7 +48,7 @@ fn void! File.reopen(&self, String filename, String mode)
|
||||
/**
|
||||
* @require self.file != null
|
||||
**/
|
||||
fn usz! File.seek(&self, isz offset, Seek seek_mode = Seek.SET)
|
||||
fn usz! File.seek(&self, isz offset, Seek seek_mode = Seek.SET) @dynamic
|
||||
{
|
||||
os::native_fseek(self.file, offset, seek_mode)!;
|
||||
return os::native_ftell(self.file);
|
||||
@@ -75,7 +74,7 @@ fn void! File.memopen(File* file, char[] data, String mode)
|
||||
/**
|
||||
* @require self.file != null
|
||||
*/
|
||||
fn void! File.write_byte(&self, char c)
|
||||
fn void! File.write_byte(&self, char c) @dynamic
|
||||
{
|
||||
if (!libc::fputc(c, self.file)) return IoError.EOF?;
|
||||
}
|
||||
@@ -83,7 +82,7 @@ fn void! File.write_byte(&self, char c)
|
||||
/**
|
||||
* @param [&inout] self
|
||||
*/
|
||||
fn void! File.close(&self) @inline
|
||||
fn void! File.close(&self) @inline @dynamic
|
||||
{
|
||||
if (self.file && libc::fclose(self.file))
|
||||
{
|
||||
@@ -117,7 +116,7 @@ fn bool File.eof(&self) @inline
|
||||
/**
|
||||
* @param [in] buffer
|
||||
*/
|
||||
fn usz! File.read(&self, char[] buffer)
|
||||
fn usz! File.read(&self, char[] buffer) @dynamic
|
||||
{
|
||||
return os::native_fread(self.file, buffer);
|
||||
}
|
||||
@@ -126,13 +125,13 @@ fn usz! File.read(&self, char[] buffer)
|
||||
* @param [out] buffer
|
||||
* @require self.file `File must be initialized`
|
||||
*/
|
||||
fn usz! File.write(&self, char[] buffer)
|
||||
fn usz! File.write(&self, char[] buffer) @dynamic
|
||||
{
|
||||
return os::native_fwrite(self.file, buffer);
|
||||
}
|
||||
|
||||
|
||||
fn char! File.read_byte(&self)
|
||||
fn char! File.read_byte(&self) @dynamic
|
||||
{
|
||||
int c = libc::fgetc(self.file);
|
||||
if (c == -1) return IoError.EOF?;
|
||||
@@ -142,17 +141,7 @@ fn char! File.read_byte(&self)
|
||||
/**
|
||||
* @require self.file `File must be initialized`
|
||||
*/
|
||||
fn void! File.flush(&self)
|
||||
fn void! File.flush(&self) @dynamic
|
||||
{
|
||||
libc::fflush(self.file);
|
||||
}
|
||||
|
||||
const StreamInterface FILESTREAM_INTERFACE = {
|
||||
.close_fn = (CloseStreamFn)&File.close,
|
||||
.seek_fn = (SeekStreamFn)&File.seek,
|
||||
.read_fn = (ReadStreamFn)&File.read,
|
||||
.read_byte_fn = (ReadByteStreamFn)&File.read_byte,
|
||||
.write_fn = (WriteStreamFn)&File.write,
|
||||
.write_byte_fn = (WriteByteStreamFn)&File.write_byte,
|
||||
.flush_fn = (FlushStreamFn)&File.flush
|
||||
};
|
||||
145
lib/std/io/io.c3
145
lib/std/io/io.c3
@@ -45,14 +45,127 @@ fault IoError
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param stream
|
||||
* @require @is_instream(stream)
|
||||
**/
|
||||
macro String! readline(stream = io::stdin(), Allocator* using = mem::heap())
|
||||
{
|
||||
bool $is_stream = $typeof(stream).typeid == InStream*.typeid;
|
||||
$if $is_stream:
|
||||
$typeof(&stream.read_byte) func = &stream.read_byte;
|
||||
char val = func((void*)stream)!;
|
||||
$else
|
||||
char val = stream.read_byte()!;
|
||||
$endif
|
||||
|
||||
if (val == '\n') return "";
|
||||
@pool(using)
|
||||
{
|
||||
DString str = dstring::tnew_with_capacity(256);
|
||||
if (val != '\r') str.append(val);
|
||||
while (1)
|
||||
{
|
||||
$if $is_stream:
|
||||
char! c = func((void*)stream);
|
||||
$else
|
||||
char! c = stream.read_byte();
|
||||
$endif
|
||||
if (catch err = c)
|
||||
{
|
||||
if (err == IoError.EOF) break;
|
||||
return err?;
|
||||
}
|
||||
if (c == '\r') continue;
|
||||
if (c == '\n') break;
|
||||
str.append_char(c);
|
||||
}
|
||||
return str.copy_str(using);
|
||||
};
|
||||
}
|
||||
|
||||
macro String! treadline(stream = io::stdin()) => readline(stream, mem::temp()) @inline;
|
||||
|
||||
/**
|
||||
* @require @is_outstream(out) "The output must implement OutStream"
|
||||
*/
|
||||
macro usz! fprint(out, x)
|
||||
{
|
||||
var $Type = $typeof(x);
|
||||
$switch ($Type)
|
||||
$case String:
|
||||
return out.write(x);
|
||||
$case ZString:
|
||||
return out.write(x.str_view());
|
||||
$case DString:
|
||||
return out.write(x.str_view());
|
||||
$default:
|
||||
$if $assignable(x, String):
|
||||
return out.write((String)x);
|
||||
$else
|
||||
return printf("%s", x, .out = out);
|
||||
$endif
|
||||
$endswitch
|
||||
}
|
||||
|
||||
fn usz! fprintf(OutStream* out, String format, args...)
|
||||
{
|
||||
Formatter formatter;
|
||||
formatter.init(&out_putstream_fn, &out);
|
||||
return formatter.vprintf(format, args);
|
||||
}
|
||||
|
||||
fn usz! fprintfn(OutStream* out, String format, args...) @maydiscard
|
||||
{
|
||||
Formatter formatter;
|
||||
formatter.init(&out_putstream_fn, &out);
|
||||
usz len = formatter.vprintf(format, args)!;
|
||||
out.write_byte('\n')!;
|
||||
if (&out.flush) out.flush()!;
|
||||
return len + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @require @is_outstream(out) "The output must implement OutStream"
|
||||
*/
|
||||
macro usz! fprintn(out, x = "")
|
||||
{
|
||||
usz len = fprint(out, x)!;
|
||||
out.write_byte('\n')!;
|
||||
$switch
|
||||
$case $typeof(out).typeid == OutStream*.typeid:
|
||||
if (&out.flush) out.flush()!;
|
||||
$case $defined(out.flush):
|
||||
out.flush()!;
|
||||
$endswitch
|
||||
return len + 1;
|
||||
}
|
||||
|
||||
macro void print(x)
|
||||
{
|
||||
(void)print_gen(stdout(), x);
|
||||
(void)fprint(io::stdout(), x);
|
||||
}
|
||||
|
||||
macro void printn(x = "")
|
||||
{
|
||||
(void)printn_gen(stdout(), x);
|
||||
(void)fprintn(io::stdout(), x);
|
||||
}
|
||||
|
||||
macro void eprint(x)
|
||||
{
|
||||
(void)fprint(io::stderr(), x);
|
||||
}
|
||||
|
||||
macro void eprintn(x)
|
||||
{
|
||||
(void)fprintn(io::stderr(), x);
|
||||
}
|
||||
|
||||
|
||||
fn void! out_putstream_fn(void* data, char c) @private
|
||||
{
|
||||
OutStream** stream = data;
|
||||
return (*stream).write_byte(c);
|
||||
}
|
||||
|
||||
fn void! out_putchar_fn(void* data @unused, char c) @private
|
||||
@@ -60,7 +173,6 @@ fn void! out_putchar_fn(void* data @unused, char c) @private
|
||||
libc::putchar(c);
|
||||
}
|
||||
|
||||
|
||||
fn usz! printf(String format, args...) @maydiscard
|
||||
{
|
||||
Formatter formatter;
|
||||
@@ -74,9 +186,30 @@ fn usz! printfn(String format, args...) @maydiscard
|
||||
formatter.init(&out_putchar_fn);
|
||||
usz len = formatter.vprintf(format, args)!;
|
||||
putchar('\n');
|
||||
io::stdout().flush()!;
|
||||
return len + 1;
|
||||
}
|
||||
|
||||
fn usz! eprintf(String format, args...) @maydiscard
|
||||
{
|
||||
Formatter formatter;
|
||||
OutStream* stream = stderr();
|
||||
formatter.init(&out_putstream_fn, &stream);
|
||||
return formatter.vprintf(format, args);
|
||||
}
|
||||
|
||||
|
||||
fn usz! eprintfn(String format, args...) @maydiscard
|
||||
{
|
||||
Formatter formatter;
|
||||
OutStream* stream = stderr();
|
||||
formatter.init(&out_putstream_fn, &stream);
|
||||
usz len = formatter.vprintf(format, args)! + 1;
|
||||
stderr().write_byte('\n')!;
|
||||
stderr().flush()!;
|
||||
return len;
|
||||
}
|
||||
|
||||
fn char[]! bprintf(char[] buffer, String format, args...) @maydiscard
|
||||
{
|
||||
Formatter formatter;
|
||||
@@ -112,21 +245,21 @@ fn void putchar(char c) @inline
|
||||
fn File* stdout()
|
||||
{
|
||||
static File file;
|
||||
if (!file.fns) file = file::from_handle(libc::stdout());
|
||||
if (!file.file) file = file::from_handle(libc::stdout());
|
||||
return &file;
|
||||
}
|
||||
|
||||
fn File* stderr()
|
||||
{
|
||||
static File file;
|
||||
if (!file.fns) file = file::from_handle(libc::stderr());
|
||||
if (!file.file) file = file::from_handle(libc::stderr());
|
||||
return &file;
|
||||
}
|
||||
|
||||
fn File* stdin()
|
||||
{
|
||||
static File file;
|
||||
if (!file.fns) file = file::from_handle(libc::stdin());
|
||||
if (!file.file) file = file::from_handle(libc::stdin());
|
||||
return &file;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,377 +1,166 @@
|
||||
module std::io;
|
||||
|
||||
def CloseStreamFn = fn void!(Stream*);
|
||||
def FlushStreamFn = fn void!(Stream*);
|
||||
def SeekStreamFn = fn usz!(Stream*, isz offset, Seek seek);
|
||||
def LenStreamFn = fn usz(Stream*);
|
||||
def AvailableStreamFn = fn usz!(Stream*);
|
||||
def ReadStreamFn = fn usz!(Stream*, char[] bytes);
|
||||
def ReadFromStreamFn = fn usz!(Stream*, Stream*);
|
||||
def ReadByteStreamFn = fn char!(Stream*);
|
||||
def PushbackByteStreamFn = fn void!(Stream*);
|
||||
def WriteStreamFn = fn usz!(Stream*, char[] bytes);
|
||||
def WriteToStreamFn = fn usz!(Stream*, Stream* out);
|
||||
def WriteByteStreamFn = fn void!(Stream*, char c);
|
||||
def DestroyStreamFn = fn void!(Stream*);
|
||||
|
||||
struct StreamInterface
|
||||
interface InStream
|
||||
{
|
||||
CloseStreamFn close_fn;
|
||||
FlushStreamFn flush_fn;
|
||||
SeekStreamFn seek_fn;
|
||||
LenStreamFn len_fn;
|
||||
AvailableStreamFn available_fn;
|
||||
ReadStreamFn read_fn;
|
||||
ReadFromStreamFn read_stream_fn;
|
||||
ReadByteStreamFn read_byte_fn;
|
||||
PushbackByteStreamFn pushback_byte_fn;
|
||||
WriteStreamFn write_fn;
|
||||
WriteToStreamFn write_stream_fn;
|
||||
WriteByteStreamFn write_byte_fn;
|
||||
DestroyStreamFn destroy_fn;
|
||||
fn void! close() @optional;
|
||||
fn usz! seek(isz offset, Seek seek) @optional;
|
||||
fn usz len() @optional;
|
||||
fn usz! available() @optional;
|
||||
fn usz! read(char[] buffer);
|
||||
fn char! read_byte();
|
||||
fn usz! write_to(OutStream* out) @optional;
|
||||
fn void! pushback_byte() @optional;
|
||||
}
|
||||
|
||||
struct Stream
|
||||
|
||||
interface OutStream
|
||||
{
|
||||
StreamInterface* fns;
|
||||
fn void! destroy() @optional;
|
||||
fn void! close() @optional;
|
||||
fn void! flush() @optional;
|
||||
fn usz! write(char[] bytes);
|
||||
fn void! write_byte(char c);
|
||||
fn usz! read_to(InStream* in) @optional;
|
||||
}
|
||||
|
||||
struct StreamWrapper
|
||||
fn usz! available(InStream* s)
|
||||
{
|
||||
inline Stream stream;
|
||||
void* data;
|
||||
}
|
||||
|
||||
fn bool Stream.supports_flush(&s) @inline => (bool)s.fns.flush_fn;
|
||||
fn bool Stream.supports_seek(&s) @inline => (bool)s.fns.seek_fn;
|
||||
fn bool Stream.supports_available(&s) @inline => s.fns.available_fn || s.fns.seek_fn;
|
||||
fn bool Stream.supports_len(&s) @inline => s.fns.len_fn || s.fns.seek_fn;
|
||||
fn bool Stream.supports_read(&s) @inline => s.fns.read_fn || s.fns.read_byte_fn;
|
||||
fn bool Stream.supports_read_from(&s) @inline => (bool)s.fns.read_stream_fn;
|
||||
fn bool Stream.supports_write_to(&s) @inline => (bool)s.fns.write_stream_fn;
|
||||
fn bool Stream.supports_pushback_byte(&s) @inline => s.fns.pushback_byte_fn || s.fns.seek_fn;
|
||||
fn bool Stream.supports_write(&s) @inline => s.fns.write_fn || s.fns.write_byte_fn;
|
||||
fn bool Stream.supports_read_byte(&s) @inline => (bool)s.fns.read_byte_fn;
|
||||
fn bool Stream.supports_write_byte(&s) @inline => (bool)s.fns.write_byte_fn;
|
||||
|
||||
fn void! Stream.destroy(&self) @inline @maydiscard
|
||||
{
|
||||
if (self.fns.destroy_fn) return self.fns.destroy_fn(self);
|
||||
return self.close();
|
||||
}
|
||||
|
||||
fn void! Stream.close(&self) @inline @maydiscard
|
||||
{
|
||||
if (CloseStreamFn func = self.fns.close_fn) return func(self);
|
||||
}
|
||||
|
||||
fn usz! Stream.seek(&self, isz offset, Seek seek) @inline
|
||||
{
|
||||
if (SeekStreamFn func = self.fns.seek_fn) return func(self, offset, seek);
|
||||
return IoError.NOT_SEEKABLE?;
|
||||
}
|
||||
|
||||
fn usz! Stream.available(&self) @inline
|
||||
{
|
||||
if (AvailableStreamFn func = self.fns.available_fn) return func(self);
|
||||
if (SeekStreamFn func = self.fns.seek_fn)
|
||||
if (&s.available) return s.available();
|
||||
if (&s.seek)
|
||||
{
|
||||
usz curr = func(self, 0, Seek.CURSOR)!;
|
||||
usz len = func(self, 0, Seek.END)!;
|
||||
func(self, curr, Seek.SET)!;
|
||||
usz curr = s.seek(0, Seek.CURSOR)!;
|
||||
usz len = s.seek(0, Seek.END)!;
|
||||
s.seek(curr, Seek.SET)!;
|
||||
return len - curr;
|
||||
}
|
||||
return IoError.NOT_SEEKABLE?;
|
||||
return 0;
|
||||
}
|
||||
|
||||
fn usz! Stream.read_any(&self, any* ref)
|
||||
macro bool @is_instream(#expr)
|
||||
{
|
||||
return self.read_all(ref.ptr[:ref.type.sizeof]);
|
||||
return $assignable(#expr, InStream*);
|
||||
}
|
||||
|
||||
macro bool @is_outstream(#expr)
|
||||
{
|
||||
return $assignable(#expr, OutStream*);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ref "the object to write."
|
||||
* @require ref.ptr != null
|
||||
* @param [&out] ref
|
||||
* @require @is_instream(stream)
|
||||
**/
|
||||
macro usz! read_any(stream, any* ref)
|
||||
{
|
||||
return read_all(stream, ((char*)ref)[:ref.type.sizeof]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param [&in] ref "the object to write."
|
||||
* @require @is_outstream(stream)
|
||||
* @ensure return == ref.type.sizeof
|
||||
*/
|
||||
fn usz! Stream.write_any(&self, any* ref)
|
||||
macro usz! write_any(stream, any* ref)
|
||||
{
|
||||
return self.write_all(ref.ptr[:ref.type.sizeof]);
|
||||
return write_all(stream, ((char*)ref)[:ref.type.sizeof]);
|
||||
}
|
||||
|
||||
fn usz! Stream.read(&self, char[] buffer)
|
||||
/**
|
||||
* @require @is_instream(stream)
|
||||
*/
|
||||
macro usz! read_all(stream, char[] buffer)
|
||||
{
|
||||
if (ReadStreamFn func = self.fns.read_fn) return func(self, buffer);
|
||||
if (ReadByteStreamFn func = self.fns.read_byte_fn)
|
||||
{
|
||||
usz len = 0;
|
||||
foreach (&cptr : buffer)
|
||||
{
|
||||
char! c = func(self);
|
||||
if (catch err = c)
|
||||
{
|
||||
case IoError.EOF: return len;
|
||||
default: return err?;
|
||||
}
|
||||
*cptr = c;
|
||||
len++;
|
||||
}
|
||||
}
|
||||
return IoError.UNSUPPORTED_OPERATION?;
|
||||
}
|
||||
|
||||
macro usz! Stream.print(&self, x) @maydiscard
|
||||
{
|
||||
return print_gen(self, x);
|
||||
}
|
||||
|
||||
macro usz! print_gen(self, x)
|
||||
{
|
||||
var $Type = $typeof(x);
|
||||
$switch ($Type)
|
||||
$case String:
|
||||
return self.write(x);
|
||||
$case ZString:
|
||||
return self.write(x.str_view());
|
||||
$case DString:
|
||||
return self.write(x.str_view());
|
||||
$default:
|
||||
$if $defined((String)x):
|
||||
return self.write((String)x);
|
||||
$else
|
||||
return printf("%s", x);
|
||||
$endif
|
||||
$endswitch
|
||||
}
|
||||
|
||||
macro usz! printn_gen(self, x) @maydiscard
|
||||
{
|
||||
usz len = print_gen(self, x)!;
|
||||
self.write_byte('\n')!;
|
||||
self.flush()!;
|
||||
return len + 1;
|
||||
}
|
||||
|
||||
macro usz! Stream.printn(&self, x) @maydiscard
|
||||
{
|
||||
return printn_gen(self, x);
|
||||
}
|
||||
|
||||
fn usz! Stream.printf(&self, String format, args...) @maydiscard
|
||||
{
|
||||
Formatter formatter;
|
||||
if (WriteByteStreamFn func_byte = self.fns.write_byte_fn)
|
||||
{
|
||||
formatter.init((OutputFn)func_byte, self);
|
||||
}
|
||||
else if (WriteStreamFn func = self.fns.write_fn)
|
||||
{
|
||||
formatter.init((OutputFn)&Stream.write_byte, self);
|
||||
}
|
||||
else
|
||||
{
|
||||
return IoError.UNSUPPORTED_OPERATION?;
|
||||
}
|
||||
return formatter.vprintf(format, args)!;
|
||||
}
|
||||
|
||||
fn usz! Stream.printfn(&self, String format, args...) @maydiscard @inline
|
||||
{
|
||||
Formatter formatter;
|
||||
if (WriteByteStreamFn func_byte = self.fns.write_byte_fn)
|
||||
{
|
||||
formatter.init((OutputFn)func_byte, self);
|
||||
}
|
||||
else if (WriteStreamFn func = self.fns.write_fn)
|
||||
{
|
||||
formatter.init((OutputFn)&Stream.write_byte, self);
|
||||
}
|
||||
else
|
||||
{
|
||||
return IoError.UNSUPPORTED_OPERATION?;
|
||||
}
|
||||
usz len = formatter.vprintf(format, args)!;
|
||||
self.write_byte('\n')!;
|
||||
self.flush()!;
|
||||
return len + 1;
|
||||
}
|
||||
|
||||
fn char! Stream.read_byte(&self) @inline
|
||||
{
|
||||
if (ReadByteStreamFn func = self.fns.read_byte_fn) return func(self);
|
||||
if (ReadStreamFn func = self.fns.read_fn)
|
||||
{
|
||||
char[1] buffer;
|
||||
usz read = func(self, &buffer)!;
|
||||
if (read != 1) return IoError.EOF?;
|
||||
return buffer[0];
|
||||
}
|
||||
return IoError.UNSUPPORTED_OPERATION?;
|
||||
}
|
||||
|
||||
fn usz! Stream.read_all(&self, char[] buffer) @inline
|
||||
{
|
||||
usz n = self.read(buffer)!;
|
||||
if (buffer.len == 0) return 0;
|
||||
usz n = stream.read(buffer)!;
|
||||
if (n != buffer.len) return IoError.UNEXPECTED_EOF?;
|
||||
return n;
|
||||
}
|
||||
|
||||
fn usz! Stream.write_all(&self, char[] buffer) @inline
|
||||
/**
|
||||
* @require @is_outstream(stream)
|
||||
*/
|
||||
macro usz! write_all(stream, char[] buffer)
|
||||
{
|
||||
usz n = self.write(buffer)!;
|
||||
if (buffer.len == 0) return 0;
|
||||
usz n = stream.write(buffer)!;
|
||||
if (n != buffer.len) return IoError.INCOMPLETE_WRITE?;
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
fn String! Stream.treadline(&self) => self.readline(mem::temp()) @inline;
|
||||
|
||||
fn String! Stream.readline(&self, Allocator* using = mem::heap())
|
||||
macro usz! @read_using_read_byte(&s, char[] buffer)
|
||||
{
|
||||
if (ReadByteStreamFn func = self.fns.read_byte_fn)
|
||||
usz len = 0;
|
||||
foreach (&cptr : buffer)
|
||||
{
|
||||
char val = func(self)!;
|
||||
if (val == '\n') return "";
|
||||
@pool(using)
|
||||
{
|
||||
DString str = dstring::tnew_with_capacity(256);
|
||||
if (val != '\r') str.append(val);
|
||||
while (1)
|
||||
{
|
||||
char! c = func(self);
|
||||
if (catch err = c)
|
||||
{
|
||||
if (err == IoError.EOF) break;
|
||||
return err?;
|
||||
}
|
||||
if (c == '\r') continue;
|
||||
if (c == '\n') break;
|
||||
str.append_char(c);
|
||||
}
|
||||
return str.copy_str(using);
|
||||
};
|
||||
char! c = s.read_byte();
|
||||
if (catch err = c)
|
||||
{
|
||||
case IoError.EOF: return len;
|
||||
default: return err?;
|
||||
}
|
||||
*cptr = c;
|
||||
len++;
|
||||
}
|
||||
if (ReadStreamFn func = self.fns.read_fn)
|
||||
{
|
||||
char[1] buff;
|
||||
if (func(self, &buff)! == 0) return IoError.EOF?;
|
||||
char val = buff[0];
|
||||
if (val == '\n') return "";
|
||||
@pool(using)
|
||||
{
|
||||
DString str = dstring::tnew_with_capacity(256);
|
||||
if (val != '\r') str.append(val);
|
||||
while (1)
|
||||
{
|
||||
usz! read = func(self, &buff);
|
||||
if (catch err = read)
|
||||
{
|
||||
if (err == IoError.EOF) break;
|
||||
return err?;
|
||||
}
|
||||
if (!read) break;
|
||||
char c = buff[0];
|
||||
if (c == '\r') continue;
|
||||
if (c == '\n') break;
|
||||
str.append_char(c);
|
||||
}
|
||||
return str.copy_str(using);
|
||||
};
|
||||
}
|
||||
return IoError.UNSUPPORTED_OPERATION?;
|
||||
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
fn usz! Stream.write(&self, char[] bytes) @inline
|
||||
macro void! @write_byte_using_write(&s, char c)
|
||||
{
|
||||
if (WriteStreamFn func = self.fns.write_fn) return func(self, bytes);
|
||||
if (WriteByteStreamFn func = self.fns.write_byte_fn)
|
||||
{
|
||||
foreach (c : bytes) func(self, c)!;
|
||||
return bytes.len;
|
||||
}
|
||||
return IoError.UNSUPPORTED_OPERATION?;
|
||||
char[1] buff = { c };
|
||||
(*s).write(&buff)!;
|
||||
}
|
||||
|
||||
fn void! Stream.write_byte(&self, char b) @inline
|
||||
|
||||
macro char! @read_byte_using_read(&s)
|
||||
{
|
||||
if (WriteByteStreamFn func = self.fns.write_byte_fn) return func(self, b);
|
||||
return IoError.UNSUPPORTED_OPERATION?;
|
||||
char[1] buffer;
|
||||
usz read = (*s).read(&buffer)!;
|
||||
if (read != 1) return IoError.EOF?;
|
||||
return buffer[0];
|
||||
}
|
||||
|
||||
fn usz! Stream.write_to(&self, Stream* to) @inline
|
||||
def ReadByteFn = fn char!();
|
||||
|
||||
|
||||
macro usz! @write_using_write_byte(&s, char[] bytes)
|
||||
{
|
||||
if (WriteToStreamFn func = self.fns.write_stream_fn) return func(self, to);
|
||||
return IoError.UNSUPPORTED_OPERATION?;
|
||||
foreach (c : bytes) s.write_byte(self, c)!;
|
||||
return bytes.len;
|
||||
}
|
||||
|
||||
fn usz! Stream.read_from(&self, Stream* from) @inline
|
||||
macro void! @pushback_using_seek(&s)
|
||||
{
|
||||
if (ReadFromStreamFn func = self.fns.read_stream_fn) return func(self, from);
|
||||
return IoError.UNSUPPORTED_OPERATION?;
|
||||
s.seek(-1, CURSOR)!;
|
||||
}
|
||||
|
||||
fn void! Stream.flush(&self) @inline @maydiscard
|
||||
fn usz! copy_to(InStream* in, OutStream* dst, char[] buffer = {})
|
||||
{
|
||||
if (FlushStreamFn func = self.fns.flush_fn) return func(self);
|
||||
return IoError.UNSUPPORTED_OPERATION?;
|
||||
}
|
||||
|
||||
fn usz! Stream.len(&self) @inline
|
||||
{
|
||||
if (LenStreamFn func = self.fns.len_fn) return func(self);
|
||||
if (SeekStreamFn func = self.fns.seek_fn)
|
||||
{
|
||||
usz curr = func(self, 0, Seek.CURSOR)!;
|
||||
usz len = func(self, 0, Seek.END)!;
|
||||
func(self, curr, Seek.SET)!;
|
||||
return len;
|
||||
}
|
||||
return IoError.NOT_SEEKABLE?;
|
||||
}
|
||||
|
||||
fn void! Stream.pushback_byte(&self) @inline
|
||||
{
|
||||
if (PushbackByteStreamFn func = self.fns.pushback_byte_fn) return func(self);
|
||||
if (SeekStreamFn func = self.fns.seek_fn)
|
||||
{
|
||||
func(self, -1, CURSOR)!;
|
||||
return;
|
||||
}
|
||||
return IoError.UNSUPPORTED_OPERATION?;
|
||||
}
|
||||
|
||||
fn void! Stream.write_string(&self, String str) @inline => (void)(self.write((char[])str)!);
|
||||
|
||||
fn usz! Stream.copy_to(&self, Stream* dst, char[] buffer = {})
|
||||
{
|
||||
if (buffer.len) return copy_through_buffer(self, dst, buffer);
|
||||
if (WriteToStreamFn func = self.fns.write_stream_fn) return func(self, dst);
|
||||
if (ReadFromStreamFn func = self.fns.read_stream_fn) return func(dst, self);
|
||||
if (buffer.len) return copy_through_buffer(in, dst, buffer);
|
||||
if (&in.write_to) return in.write_to(dst);
|
||||
if (&dst.read_to) return dst.read_to(in);
|
||||
$switch (env::MEMORY_ENV)
|
||||
$case NORMAL:
|
||||
@pool()
|
||||
{
|
||||
return copy_through_buffer(self, dst, tmalloc(char, 4096));
|
||||
return copy_through_buffer(in, dst, tmalloc(char, 4096));
|
||||
};
|
||||
$case SMALL:
|
||||
@pool()
|
||||
{
|
||||
return copy_through_buffer(self, dst, tmalloc(char, 1024));
|
||||
return copy_through_buffer(in, dst, tmalloc(char, 1024));
|
||||
};
|
||||
$case TINY:
|
||||
$case NONE:
|
||||
return copy_through_buffer(self, dst, &&(char[256]{}));
|
||||
return copy_through_buffer(in, dst, &&(char[256]{}));
|
||||
$endswitch
|
||||
}
|
||||
|
||||
macro usz! copy_through_buffer(Stream *self, Stream* dst, char[] buffer) @local
|
||||
macro usz! copy_through_buffer(InStream *in, OutStream* dst, char[] buffer) @local
|
||||
{
|
||||
usz total_copied;
|
||||
while (true)
|
||||
{
|
||||
usz! len = self.read(buffer);
|
||||
usz! len = in.read(buffer);
|
||||
if (catch err = len)
|
||||
{
|
||||
case IoError.EOF: return total_copied;
|
||||
@@ -387,9 +176,10 @@ macro usz! copy_through_buffer(Stream *self, Stream* dst, char[] buffer) @local
|
||||
const char[*] MAX_VARS @private = { [2] = 3, [4] = 5, [8] = 10 };
|
||||
|
||||
/**
|
||||
* @require @is_instream(stream)
|
||||
* @require $typeof(x_ptr).kindof == POINTER && $typeof(x_ptr).inner.kindof.is_int()
|
||||
**/
|
||||
macro usz! Stream.read_varint(&self, x_ptr)
|
||||
macro usz! read_varint(stream, x_ptr)
|
||||
{
|
||||
var $Type = $typefrom($typeof(x_ptr).inner);
|
||||
const MAX = MAX_VARS[$Type.sizeof];
|
||||
@@ -398,7 +188,7 @@ macro usz! Stream.read_varint(&self, x_ptr)
|
||||
usz n;
|
||||
for (usz i = 0; i < MAX; i++)
|
||||
{
|
||||
char! c = self.read_byte();
|
||||
char! c = stream.read_byte();
|
||||
if (catch err = c)
|
||||
{
|
||||
case IoError.EOF:
|
||||
@@ -422,11 +212,11 @@ macro usz! Stream.read_varint(&self, x_ptr)
|
||||
}
|
||||
return MathError.OVERFLOW?;
|
||||
}
|
||||
|
||||
/**
|
||||
* @require @is_outstream(stream)
|
||||
* @require $typeof(x).kindof.is_int()
|
||||
**/
|
||||
macro usz! Stream.write_varint(&self, x)
|
||||
macro usz! write_varint(stream, x)
|
||||
{
|
||||
var $Type = $typeof(x);
|
||||
const MAX = MAX_VARS[$Type.sizeof];
|
||||
@@ -439,5 +229,5 @@ macro usz! Stream.write_varint(&self, x)
|
||||
i++;
|
||||
}
|
||||
buffer[i] = (char)x;
|
||||
return self.write_all(buffer[:i + 1]);
|
||||
return write_all(stream, buffer[:i + 1]);
|
||||
}
|
||||
@@ -1,9 +1,8 @@
|
||||
module std::io;
|
||||
|
||||
struct ReadBuffer
|
||||
struct ReadBuffer (InStream)
|
||||
{
|
||||
inline Stream stream;
|
||||
Stream* wrapped_stream;
|
||||
InStream* wrapped_stream;
|
||||
char[] bytes;
|
||||
usz read_idx;
|
||||
usz write_idx;
|
||||
@@ -15,24 +14,22 @@ struct ReadBuffer
|
||||
* @require bytes.len > 0
|
||||
* @require self.bytes.len == 0 "Init may not run on already initialized data"
|
||||
**/
|
||||
fn ReadBuffer* ReadBuffer.init(&self, Stream* wrapped_stream, char[] bytes)
|
||||
fn ReadBuffer* ReadBuffer.init(&self, InStream* wrapped_stream, char[] bytes)
|
||||
{
|
||||
*self = { .stream.fns = &READBUFFER_INTERFACE, .wrapped_stream = wrapped_stream, .bytes = bytes };
|
||||
*self = { .wrapped_stream = wrapped_stream, .bytes = bytes };
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
const StreamInterface READBUFFER_INTERFACE = {
|
||||
.read_fn = (ReadStreamFn)&ReadBuffer.read,
|
||||
.read_byte_fn = (ReadByteStreamFn)&ReadBuffer.read_byte,
|
||||
};
|
||||
|
||||
fn String ReadBuffer.str_view(&self) @inline
|
||||
{
|
||||
return (String)self.bytes[self.read_idx:self.write_idx - self.read_idx];
|
||||
}
|
||||
|
||||
fn usz! ReadBuffer.read(&self, char[] bytes)
|
||||
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)
|
||||
{
|
||||
@@ -49,7 +46,7 @@ fn usz! ReadBuffer.read(&self, char[] bytes)
|
||||
return n;
|
||||
}
|
||||
|
||||
fn char! ReadBuffer.read_byte(&self)
|
||||
fn char! ReadBuffer.read_byte(&self) @dynamic
|
||||
{
|
||||
if (self.read_idx == self.write_idx) self.refill()!;
|
||||
if (self.read_idx == self.write_idx) return IoError.EOF?;
|
||||
@@ -64,10 +61,9 @@ fn void! ReadBuffer.refill(&self) @local @inline
|
||||
self.write_idx = self.wrapped_stream.read(self.bytes)!;
|
||||
}
|
||||
|
||||
struct WriteBuffer
|
||||
struct WriteBuffer (OutStream)
|
||||
{
|
||||
inline Stream stream;
|
||||
Stream* wrapped_stream;
|
||||
OutStream* wrapped_stream;
|
||||
char[] bytes;
|
||||
usz index;
|
||||
}
|
||||
@@ -78,30 +74,29 @@ struct WriteBuffer
|
||||
* @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, Stream* wrapped_stream, char[] bytes)
|
||||
fn WriteBuffer* WriteBuffer.init(&self, OutStream* wrapped_stream, char[] bytes)
|
||||
{
|
||||
*self = { .stream.fns = &WRITEBUFFER_INTERFACE, .wrapped_stream = wrapped_stream, .bytes = bytes };
|
||||
*self = { .wrapped_stream = wrapped_stream, .bytes = bytes };
|
||||
return self;
|
||||
}
|
||||
|
||||
const StreamInterface WRITEBUFFER_INTERFACE = {
|
||||
.flush_fn = (FlushStreamFn)&WriteBuffer.flush,
|
||||
.write_fn = (WriteStreamFn)&WriteBuffer.write,
|
||||
.write_byte_fn = (WriteByteStreamFn)&WriteBuffer.write_byte,
|
||||
};
|
||||
|
||||
fn String WriteBuffer.str_view(&self) @inline
|
||||
{
|
||||
return (String)self.bytes[:self.index];
|
||||
}
|
||||
|
||||
fn void! WriteBuffer.flush(&self)
|
||||
fn void! WriteBuffer.close(&self) @dynamic
|
||||
{
|
||||
self.write_pending()!;
|
||||
if (self.wrapped_stream.supports_flush()) self.wrapped_stream.flush()!;
|
||||
if (&self.wrapped_stream.close) return self.wrapped_stream.close();
|
||||
}
|
||||
|
||||
fn usz! WriteBuffer.write(&self, char[] bytes)
|
||||
fn void! WriteBuffer.flush(&self) @dynamic
|
||||
{
|
||||
self.write_pending()!;
|
||||
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)
|
||||
@@ -123,7 +118,7 @@ fn usz! WriteBuffer.write(&self, char[] bytes)
|
||||
return bytes.len;
|
||||
}
|
||||
|
||||
fn void! WriteBuffer.write_byte(&self, char c)
|
||||
fn void! WriteBuffer.write_byte(&self, char c) @dynamic
|
||||
{
|
||||
usz n = self.bytes.len - self.index;
|
||||
if (n == 0) self.write_pending()!;
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
module std::io;
|
||||
import std::math;
|
||||
|
||||
struct ByteBuffer
|
||||
struct ByteBuffer (InStream, OutStream)
|
||||
{
|
||||
inline Stream stream;
|
||||
Allocator* allocator;
|
||||
usz max_read;
|
||||
char[] bytes;
|
||||
@@ -19,7 +18,7 @@ struct ByteBuffer
|
||||
**/
|
||||
fn ByteBuffer*! ByteBuffer.init(&self, usz max_read, usz initial_capacity = 16, Allocator* using = mem::heap())
|
||||
{
|
||||
*self = { .stream.fns = &BYTEBUFFER_INTERFACE, .allocator = using, .max_read = max_read };
|
||||
*self = { .allocator = using, .max_read = max_read };
|
||||
initial_capacity = max(initial_capacity, 16);
|
||||
self.grow(initial_capacity)!;
|
||||
return self;
|
||||
@@ -36,7 +35,7 @@ fn ByteBuffer*! ByteBuffer.tinit(&self, usz max_read, usz initial_capacity = 16)
|
||||
**/
|
||||
fn ByteBuffer*! ByteBuffer.init_with_buffer(&self, char[] buf)
|
||||
{
|
||||
*self = { .stream.fns = &BYTEBUFFER_INTERFACE, .max_read = buf.len, .bytes = buf };
|
||||
*self = { .max_read = buf.len, .bytes = buf };
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -46,16 +45,7 @@ fn void ByteBuffer.free(&self)
|
||||
*self = {};
|
||||
}
|
||||
|
||||
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)
|
||||
fn usz! ByteBuffer.write(&self, char[] bytes) @dynamic
|
||||
{
|
||||
usz cap = self.bytes.len - self.write_idx;
|
||||
if (cap < bytes.len) self.grow(bytes.len)!;
|
||||
@@ -64,7 +54,7 @@ fn usz! ByteBuffer.write(&self, char[] bytes)
|
||||
return bytes.len;
|
||||
}
|
||||
|
||||
fn void! ByteBuffer.write_byte(&self, char c)
|
||||
fn void! ByteBuffer.write_byte(&self, char c) @dynamic
|
||||
{
|
||||
usz cap = self.bytes.len - self.write_idx;
|
||||
if (cap == 0) self.grow(1)!;
|
||||
@@ -72,7 +62,7 @@ fn void! ByteBuffer.write_byte(&self, char c)
|
||||
self.write_idx++;
|
||||
}
|
||||
|
||||
fn usz! ByteBuffer.read(&self, char[] bytes)
|
||||
fn usz! ByteBuffer.read(&self, char[] bytes) @dynamic
|
||||
{
|
||||
usz readable = self.write_idx - self.read_idx;
|
||||
if (readable == 0)
|
||||
@@ -88,7 +78,7 @@ fn usz! ByteBuffer.read(&self, char[] bytes)
|
||||
return n;
|
||||
}
|
||||
|
||||
fn char! ByteBuffer.read_byte(&self)
|
||||
fn char! ByteBuffer.read_byte(&self) @dynamic
|
||||
{
|
||||
usz readable = self.write_idx - self.read_idx;
|
||||
if (readable == 0)
|
||||
@@ -106,7 +96,7 @@ fn char! ByteBuffer.read_byte(&self)
|
||||
/*
|
||||
* Only the last byte of a successful read can be pushed back.
|
||||
*/
|
||||
fn void! ByteBuffer.pushback_byte(&self)
|
||||
fn void! ByteBuffer.pushback_byte(&self) @dynamic
|
||||
{
|
||||
if (!self.has_last) return IoError.EOF?;
|
||||
assert(self.read_idx > 0);
|
||||
@@ -114,13 +104,14 @@ fn void! ByteBuffer.pushback_byte(&self)
|
||||
self.has_last = false;
|
||||
}
|
||||
|
||||
fn void! ByteBuffer.seek(&self, isz offset, Seek seek)
|
||||
fn usz! ByteBuffer.seek(&self, isz offset, Seek seek) @dynamic
|
||||
{
|
||||
switch (seek)
|
||||
{
|
||||
case SET:
|
||||
if (offset < 0 || offset > self.write_idx) return IoError.INVALID_POSITION?;
|
||||
self.read_idx = offset;
|
||||
return offset;
|
||||
case CURSOR:
|
||||
if ((offset < 0 && self.read_idx < -offset) ||
|
||||
(offset > 0 && self.read_idx + offset > self.write_idx)) return IoError.INVALID_POSITION?;
|
||||
@@ -129,9 +120,10 @@ fn void! ByteBuffer.seek(&self, isz offset, Seek seek)
|
||||
if (offset < 0 || offset > self.write_idx) return IoError.INVALID_POSITION?;
|
||||
self.read_idx = self.write_idx - offset;
|
||||
}
|
||||
return self.read_idx;
|
||||
}
|
||||
|
||||
fn usz! ByteBuffer.available(&self) @inline
|
||||
fn usz! ByteBuffer.available(&self) @inline @dynamic
|
||||
{
|
||||
return self.write_idx - self.read_idx;
|
||||
}
|
||||
|
||||
@@ -1,19 +1,23 @@
|
||||
module std::io;
|
||||
|
||||
struct ByteReader
|
||||
struct ByteReader (InStream)
|
||||
{
|
||||
inline Stream stream;
|
||||
char[] bytes;
|
||||
usz index;
|
||||
}
|
||||
|
||||
fn usz ByteReader.len(&self) @dynamic
|
||||
{
|
||||
return self.bytes.len;
|
||||
}
|
||||
|
||||
fn ByteReader* ByteReader.init(&self, char[] bytes)
|
||||
{
|
||||
*self = { .stream = { &BYTEREADER_INTERFACE }, .bytes = bytes };
|
||||
*self = { .bytes = bytes };
|
||||
return self;
|
||||
}
|
||||
|
||||
fn usz! ByteReader.read(&self, char[] bytes)
|
||||
fn usz! ByteReader.read(&self, char[] bytes) @dynamic
|
||||
{
|
||||
if (self.index >= self.bytes.len) return IoError.EOF?;
|
||||
usz len = min(self.bytes.len - self.index, bytes.len);
|
||||
@@ -23,19 +27,19 @@ fn usz! ByteReader.read(&self, char[] bytes)
|
||||
return len;
|
||||
}
|
||||
|
||||
fn char! ByteReader.read_byte(&self)
|
||||
fn char! ByteReader.read_byte(&self) @dynamic
|
||||
{
|
||||
if (self.index >= self.bytes.len) return IoError.EOF?;
|
||||
return self.bytes[self.index++];
|
||||
}
|
||||
|
||||
fn void! ByteReader.pushback_byte(&self)
|
||||
fn void! ByteReader.pushback_byte(&self) @dynamic
|
||||
{
|
||||
if (!self.index) return IoError.INVALID_PUSHBACK?;
|
||||
self.index--;
|
||||
}
|
||||
|
||||
fn usz! ByteReader.seek(&self, isz offset, Seek seek)
|
||||
fn usz! ByteReader.seek(&self, isz offset, Seek seek) @dynamic
|
||||
{
|
||||
isz new_index;
|
||||
switch (seek)
|
||||
@@ -49,7 +53,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_to(&self, OutStream* writer) @dynamic
|
||||
{
|
||||
if (self.index >= self.bytes.len) return 0;
|
||||
usz written = writer.write(self.bytes[self.index..])!;
|
||||
@@ -58,19 +62,7 @@ fn usz! ByteReader.write_stream(&self, Stream* writer)
|
||||
return written;
|
||||
}
|
||||
|
||||
fn usz ByteReader.available(&self) @inline
|
||||
fn usz! ByteReader.available(&self) @inline @dynamic
|
||||
{
|
||||
return max(0, self.bytes.len - self.index);
|
||||
}
|
||||
|
||||
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(),
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
@@ -1,8 +1,7 @@
|
||||
module std::io;
|
||||
|
||||
struct ByteWriter
|
||||
struct ByteWriter (OutStream)
|
||||
{
|
||||
inline Stream stream;
|
||||
char[] bytes;
|
||||
usz index;
|
||||
Allocator* allocator;
|
||||
@@ -16,13 +15,13 @@ struct ByteWriter
|
||||
**/
|
||||
fn ByteWriter* ByteWriter.init(&self, Allocator* using = mem::heap())
|
||||
{
|
||||
*self = { .stream.fns = &BYTEWRITER_INTERFACE, .bytes = {}, .allocator = using };
|
||||
*self = { .bytes = {}, .allocator = using };
|
||||
return self;
|
||||
}
|
||||
|
||||
fn ByteWriter* ByteWriter.init_buffer(&self, char[] data)
|
||||
{
|
||||
*self = { .stream.fns = &BYTEWRITER_INTERFACE, .bytes = data, .allocator = null };
|
||||
*self = { .bytes = data, .allocator = null };
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -35,7 +34,7 @@ fn ByteWriter* ByteWriter.tinit(&self)
|
||||
return self.init(mem::temp());
|
||||
}
|
||||
|
||||
fn void ByteWriter.destroy(&self)
|
||||
fn void! ByteWriter.destroy(&self) @dynamic
|
||||
{
|
||||
if (!self.allocator) return;
|
||||
if (void* ptr = self.bytes.ptr) free(ptr, .using = self.allocator);
|
||||
@@ -57,7 +56,7 @@ fn void! ByteWriter.ensure_capacity(&self, usz len) @inline
|
||||
self.bytes = new_ptr[:new_capacity];
|
||||
}
|
||||
|
||||
fn usz! ByteWriter.write(&self, char[] bytes)
|
||||
fn usz! ByteWriter.write(&self, char[] bytes) @dynamic
|
||||
{
|
||||
self.ensure_capacity(self.index + bytes.len)!;
|
||||
mem::copy(&self.bytes[self.index], bytes.ptr, bytes.len);
|
||||
@@ -65,7 +64,7 @@ fn usz! ByteWriter.write(&self, char[] bytes)
|
||||
return bytes.len;
|
||||
}
|
||||
|
||||
fn void! ByteWriter.write_byte(&self, char c)
|
||||
fn void! ByteWriter.write_byte(&self, char c) @dynamic
|
||||
{
|
||||
self.ensure_capacity(self.index + 1)!;
|
||||
self.bytes[self.index++] = c;
|
||||
@@ -75,10 +74,10 @@ 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, InStream* reader) @dynamic
|
||||
{
|
||||
usz start_index = self.index;
|
||||
if (reader.supports_available())
|
||||
if (&reader.available)
|
||||
{
|
||||
while (usz available = reader.available()!)
|
||||
{
|
||||
@@ -110,11 +109,3 @@ fn usz! ByteWriter.read_from(&self, Stream* reader)
|
||||
// Otherwise go another round
|
||||
}
|
||||
}
|
||||
|
||||
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,38 +0,0 @@
|
||||
module std::io;
|
||||
|
||||
struct DStringStream
|
||||
{
|
||||
inline Stream stream;
|
||||
DString* wrapped_string;
|
||||
}
|
||||
|
||||
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,9 +1,8 @@
|
||||
module std::io;
|
||||
|
||||
struct LimitReader
|
||||
struct LimitReader (InStream)
|
||||
{
|
||||
inline Stream stream;
|
||||
Stream* wrapped_stream;
|
||||
InStream* wrapped_stream;
|
||||
usz limit;
|
||||
}
|
||||
|
||||
@@ -11,13 +10,19 @@ struct LimitReader
|
||||
* @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)
|
||||
fn LimitReader* LimitReader.init(&self, InStream* wrapped_stream, usz limit)
|
||||
{
|
||||
*self = { .stream.fns = &LIMITREADER_INTERFACE, .wrapped_stream = wrapped_stream, .limit = limit };
|
||||
*self = { .wrapped_stream = wrapped_stream, .limit = limit };
|
||||
return self;
|
||||
}
|
||||
|
||||
fn usz! LimitReader.read(&self, char[] bytes)
|
||||
fn void! LimitReader.close(&self) @dynamic
|
||||
{
|
||||
if (&self.wrapped_stream.close) return self.wrapped_stream.close();
|
||||
}
|
||||
|
||||
|
||||
fn usz! LimitReader.read(&self, char[] bytes) @dynamic
|
||||
{
|
||||
if (self.limit == 0) return IoError.EOF?;
|
||||
usz m = min(bytes.len, self.limit);
|
||||
@@ -26,20 +31,14 @@ fn usz! LimitReader.read(&self, char[] bytes)
|
||||
return n;
|
||||
}
|
||||
|
||||
fn char! LimitReader.read_byte(&self)
|
||||
fn char! LimitReader.read_byte(&self) @dynamic
|
||||
{
|
||||
if (self.limit == 0) return IoError.EOF?;
|
||||
defer try self.limit--;
|
||||
return self.wrapped_stream.read_byte();
|
||||
}
|
||||
|
||||
fn usz LimitReader.available(&self) @inline
|
||||
fn usz! LimitReader.available(&self) @inline @dynamic
|
||||
{
|
||||
return self.limit;
|
||||
}
|
||||
|
||||
const StreamInterface LIMITREADER_INTERFACE = {
|
||||
.read_fn = (ReadStreamFn)&LimitReader.read,
|
||||
.read_byte_fn = (ReadByteStreamFn)&LimitReader.read_byte,
|
||||
.available_fn = fn(s) => ((LimitReader*)s).available(),
|
||||
};
|
||||
}
|
||||
@@ -1,9 +1,8 @@
|
||||
module std::io;
|
||||
|
||||
struct Scanner
|
||||
struct Scanner (InStream)
|
||||
{
|
||||
inline Stream stream;
|
||||
Stream* wrapped_stream;
|
||||
InStream* wrapped_stream;
|
||||
char[] buf;
|
||||
usz pattern_idx;
|
||||
usz read_idx;
|
||||
@@ -16,23 +15,17 @@ struct Scanner
|
||||
*
|
||||
* @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* stream, char[] buffer)
|
||||
fn void Scanner.init(&self, InStream* stream, char[] buffer)
|
||||
{
|
||||
*self = { .stream.fns = &SCANNER_INTERFACE, .wrapped_stream = stream, .buf = buffer };
|
||||
*self = { .wrapped_stream = stream, .buf = buffer };
|
||||
}
|
||||
|
||||
const StreamInterface SCANNER_INTERFACE = {
|
||||
.read_fn = (ReadStreamFn)&Scanner.read,
|
||||
.read_byte_fn = (ReadByteStreamFn)&Scanner.read_byte,
|
||||
};
|
||||
|
||||
/**
|
||||
* Return and clear any remaining unscanned data.
|
||||
**/
|
||||
fn char[] Scanner.flush(&self)
|
||||
fn char[] Scanner.flush(&self) @dynamic
|
||||
{
|
||||
assert(self.read_idx >= self.pattern_idx);
|
||||
usz n = self.read_idx - self.pattern_idx;
|
||||
@@ -42,6 +35,11 @@ fn char[] Scanner.flush(&self)
|
||||
return buf;
|
||||
}
|
||||
|
||||
fn void! Scanner.close(&self) @dynamic
|
||||
{
|
||||
if (&self.wrapped_stream.close) return self.wrapped_stream.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Scan the stream for the next split character and return data up to the match.
|
||||
* @require pattern.len > 0 "Non-empty pattern required."
|
||||
@@ -102,7 +100,7 @@ macro usz! Scanner.refill(&self, buf) @private
|
||||
return n;
|
||||
}
|
||||
|
||||
fn usz! Scanner.read(&self, char[] bytes)
|
||||
fn usz! Scanner.read(&self, char[] bytes) @dynamic
|
||||
{
|
||||
usz n;
|
||||
if (self.pattern_idx < self.read_idx)
|
||||
@@ -116,11 +114,11 @@ fn usz! Scanner.read(&self, char[] bytes)
|
||||
return n;
|
||||
}
|
||||
|
||||
fn char! Scanner.read_byte(&self)
|
||||
fn char! Scanner.read_byte(&self) @dynamic
|
||||
{
|
||||
if (self.pattern_idx < self.read_idx)
|
||||
{
|
||||
return self.buf[self.pattern_idx++];
|
||||
}
|
||||
return self.wrapped_stream.read_byte();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,8 @@ module std::net @if(os::SUPPORTS_INET);
|
||||
import std::io;
|
||||
import libc;
|
||||
|
||||
struct Socket
|
||||
struct Socket (InStream, OutStream)
|
||||
{
|
||||
inline Stream stream;
|
||||
NativeSocket sock;
|
||||
Socklen_t ai_addrlen;
|
||||
// TODO proper way to get the size of sockaddr_storage
|
||||
@@ -77,7 +76,7 @@ fn ulong! poll(Poll[] polls, Duration timeout)
|
||||
|
||||
macro Socket new_socket(fd, ai)
|
||||
{
|
||||
Socket sock = { .stream.fns = &SOCKETSTREAM_INTERFACE, .sock = fd, .ai_addrlen = ai.ai_addrlen };
|
||||
Socket sock = { .sock = fd, .ai_addrlen = ai.ai_addrlen };
|
||||
assert(sock.ai_addr_storage.len >= ai.ai_addrlen, "storage %d < addrlen %d", sock.ai_addr_storage.len, ai.ai_addrlen);
|
||||
mem::copy(&sock.ai_addr_storage, (void*)ai.ai_addr, ai.ai_addrlen);
|
||||
return sock;
|
||||
@@ -93,12 +92,6 @@ enum SocketOption : char (CInt value)
|
||||
DONTROUTE (os::SO_DONTROUTE),
|
||||
}
|
||||
|
||||
const StreamInterface SOCKETSTREAM_INTERFACE = {
|
||||
.read_fn = (ReadStreamFn)&Socket.read,
|
||||
.write_fn = (WriteStreamFn)&Socket.write,
|
||||
.close_fn = (CloseStreamFn)&Socket.close,
|
||||
};
|
||||
|
||||
fn bool! Socket.get_broadcast(&self) => self.get_option(BROADCAST);
|
||||
fn bool! Socket.get_keepalive(&self) => self.get_option(KEEPALIVE);
|
||||
fn bool! Socket.get_reuseaddr(&self) => self.get_option(REUSEADDR);
|
||||
@@ -126,21 +119,29 @@ fn bool! Socket.get_option(&self, SocketOption option)
|
||||
return (bool)flag;
|
||||
}
|
||||
|
||||
fn usz! Socket.read(&self, char[] bytes)
|
||||
fn usz! Socket.read(&self, char[] bytes) @dynamic
|
||||
{
|
||||
isz n = libc::read((Fd)self.sock, bytes.ptr, bytes.len);
|
||||
if (n < 0) return NetError.READ_FAILED?;
|
||||
return (usz)n;
|
||||
}
|
||||
|
||||
fn usz! Socket.write(&self, char[] bytes)
|
||||
fn char! Socket.read_byte(&self) @dynamic => io::@read_byte_using_read(self);
|
||||
|
||||
fn usz! Socket.write(&self, char[] bytes) @dynamic
|
||||
{
|
||||
isz n = libc::write((Fd)self.sock, bytes.ptr, bytes.len);
|
||||
if (n < 0) return NetError.WRITE_FAILED?;
|
||||
return (usz)n;
|
||||
}
|
||||
|
||||
fn void! Socket.close(&self) @inline
|
||||
fn void! Socket.write_byte(&self, char byte) @dynamic => io::@write_byte_using_write(self, byte);
|
||||
|
||||
fn void! Socket.destroy(&self) @dynamic
|
||||
{
|
||||
self.close()!;
|
||||
}
|
||||
fn void! Socket.close(&self) @inline @dynamic
|
||||
{
|
||||
self.sock.close()!;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user