commit 3b4410e5e63327b941e2fc0e3a4339ca75009b16
parent 6b851eaed490274d17c5cd7eb375a8bd064fad7f
Author: Drew DeVault <sir@cmpwn.com>
Date: Sun, 31 Jan 2021 11:32:41 -0500
io: add initial stream abstraction
Diffstat:
A | io/stream.ha | | | 53 | +++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | io/types.ha | | | 39 | +++++++++++++++++++++++++++++++++++++++ |
2 files changed, 92 insertions(+), 0 deletions(-)
diff --git a/io/stream.ha b/io/stream.ha
@@ -0,0 +1,53 @@
+// A stream of bytes which supports some subset of read, write, close, or seek
+// operations. To create a custom stream, embed this type as the first member of
+// a struct with user-specific data and fill out these fields as appropriate.
+//
+// type my_stream = struct {
+// io::stream,
+// fd: int,
+// };
+//
+// fn open(path: str) *io::stream = {
+// let fd = // ...
+// let stream = alloc(*my_stream, my_stream {
+// name: strings::dup(path),
+// reader: &my_stream_read,
+// writer: &my_stream_write,
+// closer: &my_stream_close,
+// fd: fd,
+// ...
+// });
+// return &stream.stream;
+// };
+export type stream = struct {
+ name: str,
+ reader: nullable *reader,
+ writer: nullable *writer,
+ closer: nullable *closer,
+};
+
+// Reads up to len(buf) bytes from the reader into the given buffer, returning
+// the number of bytes read.
+export fn read(s: *stream, buf: []u8) (size | error) = {
+ return match (s.reader) {
+ null => unsupported: error,
+ r: *reader => r(s, buf),
+ };
+};
+
+// Writes up to len(buf) bytes to the stream from the given buffer, returning
+// the number of bytes written.
+export fn write(s: *stream, buf: const []u8) (size | error) = {
+ return match (s.writer) {
+ null => unsupported: error,
+ w: *writer => w(s, buf),
+ };
+};
+
+// Closes the stream.
+export fn close(s: *stream, buf: []u8) (error | void) = {
+ return match (s.closer) {
+ null => unsupported: error,
+ c: *closer => c(s),
+ };
+};
diff --git a/io/types.ha b/io/types.ha
@@ -0,0 +1,39 @@
+// An error produced by the underlying source.
+export type os_error = struct {
+ string: *fn(data: *void) str,
+ data: *void,
+};
+
+// An error indicating that the underlying stream has been closed.
+export type closed = void;
+
+// An error indicating that the requested operation is not supported.
+export type unsupported = void;
+
+// Any error which may be returned from an I/O function.
+export type error = (os_error | closed | unsupported);
+
+// Converts an I/O error into a user-friendly string.
+export fn errstr(err: error) str = {
+ return match (err) {
+ err: os_error => err.string(err.data),
+ closed => "This stream has been closed",
+ unsupported => "The requested operation is not supported",
+ };
+};
+
+// The interface for a stream which can be read from. Reads up to len(buf)
+// bytes from the reader into the given buffer, returning the number of bytes
+// read or an error.
+export type reader = fn(s: *stream, buf: []u8) (size | error);
+
+// The interface for a stream which can be written to. Writes up to len(buf)
+// bytes to the writer from the given buffer, returning the number of bytes
+// written or an error.
+export type writer = fn(s: *stream, buf: const []u8) (size | error);
+
+// The interface for a stream which can be closed. This function should close
+// the underlying resources and free everything except for the stream pointer
+// itself. The other stream functions may be called after close is called; it is
+// their responsibility to return [io::closed] in this case.
+export type closer = fn(s: *stream) void;