#import "std/io"
Input and output is handled by generic stream interface containing callbacks for read, write and seek operations. The stream itself can contain any data needed (i.e. memory buffer, handle to file, etc.), generic functionality is handled via virtual table containing pointers to the implementation of all needed (supported) stream API functions.
#import "std/io"
#import "std/print"
#import "std/math"
#import "std/string"
// Custom stream implementation based on Stream.
MyStream :: struct #base Stream {
// Preallocated static buffer.
buffer: [64]u8;
// Current position in the buffer array.
position: s64;
}
// Virtual table of the stream setting up stream API functions. Our implementation
// does not support seeking, so the seek function is null.
MY_STRAM_VTABLE :: StreamVTable.{
read = auto &my_read,
write = auto &my_write
};
// Actual read function implementation.
my_read :: fn (stream: *MyStream, dest: *u8, bytes_to_read: s64) (s64, Error) {
size := min(stream.position, bytes_to_read);
stream.position -= size;
if stream.position < 0 {
size -= stream.position;
stream.position = 0;
}
if size > 0 {
memcpy(dest, &stream.buffer[stream.position], auto size);
}
return size, OK;
}
// Actual write function implementation.
my_write :: fn (stream: *MyStream, src: *u8, bytes_to_write: s64) (s64, Error) {
size :: min(stream.buffer.len - stream.position, bytes_to_write);
if size > 0 {
// size may be zero even in case the buffer is full.
memcpy(&stream.buffer[stream.position], src, auto size);
stream.position += size;
}
return size, OK;
}
init_stream :: fn (stream: *MyStream) {
stream.vtable = &MY_STRAM_VTABLE;
stream.position = 0;
}
main :: fn () s32 {
stream: MyStream #noinit;
init_stream(&stream);
// Use of the IO API.
write_string(&stream, "Hello");
write_string(&stream, "World");
str: string;
defer str_terminate(&str);
read_string(&stream, &str);
print("%\n", str);
return 0;
}
Stream :: struct {
vtable: *StreamVTable;
}
File: io.bl
StreamVTable :: struct {
read: *fn (stream: *Stream, dest: *u8, bytes_to_write: s64) (bytes_read: s64, err: Error);
write: *fn (stream: *Stream, src: *u8, bytes_to_read: s64) (bytes: s64, err: Error);
seek: *fn (stream: *Stream, locator: StreamLocator, offset: s64) (position: s64, err: Error);
flush: *fn (stream: *Stream) Error;
}
File: io.bl
StreamLocator :: enum {
CURRENT;
BEGIN;
END;
}
Stream seek offset locator.
File: io.bl
write :: fn (stream: *Stream, src: *u8, bytes_to_write: s64) (_0: s64, _1: Error) #inline
Write bytes_to_write count of bytes from the str into the stream. Returns
count of actually written bytes or an error.
File: io.bl
write_data :: fn (stream: *Stream, data: []u8, bytes_to_write :: S64_MAX) (_0: s64, _1: Error) #inline
Write the data slice into the stream, the bytes_to_write can be specified to limit count
of written bytes. Returns count of actually written bytes or an error.
File: io.bl
write_string :: fn (stream: *Stream, str: string_view, bytes_to_write :: S64_MAX) (_0: s64, _1: Error) #inline
Write the data string into the stream, the bytes_to_write can be specified to limit count
of written bytes. Returns count of actually written bytes or an error.
File: io.bl
write_all :: fn (stream: *Stream, src: *u8, bytes_to_write: s64) Error
File: io.bl
write_value :: fn (stream: *Stream, v: *?T) Error #inline
File: io.bl
read :: fn (stream: *Stream, dest: *u8, bytes_to_read: s64) (_0: s64, _1: Error) #inline
Read bytes_to_read count of bytes from the stream into dest memory. Returns count of actually
read bytes or an error.
File: io.bl
read_data :: fn (stream: *Stream, dest: *[..]u8, bytes_to_read : s64: S64_MAX, buffer_size :: 512) Error
Read bytes_to_read count of bytes from the stream into dest dynamic array. Internal buffer size may
be customized by buffer_size argument.
Return an error in case reading failed.
File: io.bl
read_string :: fn (stream: *Stream, dest: *string, bytes_to_read : s64: S64_MAX, buffer_size :: 512) Error
Read bytes_to_read count of bytes from the stream into dest. Internal buffer size may be
customized by buffer_size argument.
Return and error in case reading failed.
File: io.bl
read_all :: fn (stream: *Stream, dest: *u8, bytes_to_read: s64, buffer_size :: 512) Error
File: io.bl
read_whole :: fn (stream: *Stream, dest: *[..]u8, size_limit_bytes : s64: -1) Error
Loads context of the whole (from BEGIN locator to END) stream into dest dynamic array. The input stream must
be readable and seekable.
The size_limit_bytes might be specified to limit the maximum allowed count of bytes to read. Error is generated
in case the stream content is bigger then the limit, and no reading is done in such a case. The size_limit_bytes
is ignored when set to -1 (default).
Stream locator position is preserved.
File: io.bl
read_value :: fn (stream: *Stream, v: *?T) Error #inline
File: io.bl
seek :: fn (stream: *Stream, locator :: StreamLocator.CURRENT, offset : s64: 0) (position: s64, err: Error)
Set the stream pointer position to the offset value relative to the stream locator. Returns
the pointer position or an error.
File: io.bl
flush :: fn (stream: *Stream) Error
Flush all buffered stream data.
File: io.bl
copy_stream :: fn (dest: *Stream, src: *Stream, buffer_size :: 512) Error
Copy the whole content from current position in stream src to the stream dest (starting at current position in dest).
If copying was successful, src stream position should points to the src stream end otherwise error is returned.
File: io.bl
get_stream_size :: fn (stream: *Stream) (size: s64, err: Error)
Resolve total size of data in the stream in bytes. The stream must be seakable (stream.seek function
is not null).
The size is calculated as difference between StreamLocator.BEGIN and StreamLocator.END positions.
The original locator position is restored even if function fails with error.
In case of any error, 0 size is returned.
File: io.bl