1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
|
// SPDX-License-Identifier: MPL-2.0
// (c) Hare authors <https://harelang.org>
// TODO: Examine the ABI constraints of [[handle]]. Would it be better to make
// stream an integer representing an internal handle into a stream table? This
// would reduce performance for streams somewhat via the indirect lookup, but
// improve the ABI performance for files.
// An I/O handle is a resource which I/O operations may be performed on. It is
// either a [[stream]], which is a userspace I/O abstraction, or a [[file]],
// which is backed by a resource on the host OS, such as a file descriptor.
export type handle = (file | *stream);
// Reads up to len(buf) bytes from a [[handle]] into the given buffer, returning
// the number of bytes read.
export fn read(h: handle, buf: []u8) (size | EOF | error) = {
match (h) {
case let fd: file =>
return fd_read(fd, buf);
case let st: *stream =>
return st_read(st, buf);
};
};
// Writes up to len(buf) bytes to the [[handle]] from the given buffer,
// returning the number of bytes written.
export fn write(h: handle, buf: const []u8) (size | error) = {
match (h) {
case let fd: file =>
return fd_write(fd, buf);
case let st: *stream =>
return st_write(st, buf);
case =>
abort();
};
};
// Closes a [[handle]]. No further operations against this handle are permitted
// after calling this function. Closing a file handle can fail only under
// certain conditions (for example, closing a file twice, or an interrupted
// syscall). However, the user should not attempt to close the file again on
// failure - at best the user should print a diagnostic message and move on. See
// close(2) for details.
export fn close(h: handle) (void | error) = {
match (h) {
case let fd: file =>
fd_close(fd)?;
case let st: *stream =>
st_close(st)?;
};
};
// Sets the offset within a [[handle]], returning the new offset. The new offset
// is obtained by adding [[off]] to the position specified by [[whence]].
export fn seek(h: handle, off: off, w: whence) (off | error) = {
match (h) {
case let fd: file =>
return fd_seek(fd, off, w);
case let st: *stream =>
return st_seek(st, off, w);
};
};
// Returns the current offset within a [[handle]].
export fn tell(h: handle) (off | error) = {
return seek(h, 0, whence::CUR);
};
|