Skip to main content

41  io standard library

The io module provides high-performance, buffered input and formatted output for file descriptors, standard streams, and sockets.

#use io

41.1 Standard descriptors and output

Descriptor Value Purpose
io::STDIN 0 Standard input
io::STDOUT 1 Standard output
io::STDERR 2 Standard error

41.1.1 Standard status and error constants

Constant Value Description
io::EOF 0 Stream end-of-file
io::EINTR 4 Interrupted system call (retried automatically by io operations)
io::EBADF 9 Bad file descriptor
io::EAGAIN 11 Resource temporarily unavailable / would block
io::EWOULDBLOCK 11 Alias for io::EAGAIN

41.1.2 Output functions

Function Signature Description Example
io::out(x) #! T: Type, T => () Prints value or space-separated record + newline to STDOUT io::out(("Result:", 42))
io::err(x) #! T: Type, T => () Prints value or space-separated record + newline to STDERR io::err(("Error:", code))
io::outf(val, fmt) #! T: Type, T, String => () Formatted output to STDOUT replacing {} placeholders with value io::outf((10, <+>), "Val: {}, Flag: {}")
io::errf(val, fmt) #! T: Type, T, String => () Formatted output to STDERR replacing {} placeholders with value io::errf(line, "Failed at line {}")
io::write(fd, s) Int, String => Int Raw length-aware write of String s to descriptor fd, returns bytes written io::write(io::STDOUT, "raw\n")
#use io

// Multi-argument printing (records print space-separated):
io::out(("Server starting on port", 8080))

// Placeholder formatting:
io::outf(("127.0.0.1", 9000), "Client connected from {}:{}")

41.2 Buffered Reader API

io::reader(fd) wraps a file descriptor in a buffered reader (default buffer 4096 bytes). All read methods return the optional ramification < String | > or < Int | >, where the positive branch carries available data and the absent branch <--> indicates that no data is currently available (due to EOF, nonblocking would-block, or error):

Function Signature Return Type Description
io::reader(fd) Int => Reader Reader Creates Reader with default 4 KB buffer
io::reader_with_cap(fd, cap) Int, Int => Reader Reader Creates Reader with custom buffer size
io::read(r, max) Reader, Int => < String | > < String | > Reads available buffer chunk up to max bytes
io::read_all(r, max) Reader, Int => < String | > < String | > Drains stream completely up to max bytes
io::read_byte(r) Reader => < Int | > < Int | > Reads next byte code (0..255) or <-->
io::read_until(r, delim, max) Reader, Int, Int => < String | > < String | > Reads until delimiter byte is encountered
io::read_line(r, max) Reader, Int => < String | > < String | > Reads until newline (\n or \r\n)

41.2.1 Reader state inspection

When a read operation returns <-->, inspect the reader’s state to distinguish between EOF, would-block on nonblocking descriptors, and unhandled read errors:

Function Signature Return Type Description
io::reader_eof(r) Reader => <> <> True (<+>) if clean EOF has been reached
io::reader_err(r) Reader => Int Int Returns errno of the last I/O failure (0 if none)
io::reader_would_block(r) Reader => <> <> True (<+>) if the last read on a nonblocking fd would block (EAGAIN/EWOULDBLOCK)
io::reader_has_err(r) Reader => <> <> True (<+>) if an unhandled read error occurred (err != 0)
io::reader_clear(r) Reader => () () Resets error and EOF state flags on reader

41.2.2 Nonblocking contract

On nonblocking file descriptors (O_NONBLOCK), when no data is ready: - Read methods return the absent branch <-->. - io::reader_would_block(r) evaluates to <+>. - io::reader_err(r) is set to io::EAGAIN (11). - io::reader_eof(r) evaluates to <->.

Callers can check io::reader_would_block(r) to yield or wait on readiness notifications (such as epoll or poll), resuming read operations once data arrives. Interrupted calls (EINTR) are automatically retried internally.

41.3 Buffered input examples

41.3.1 Reading line by line

#use io

r = io::reader(io::STDIN)

0.. @
   line_res = io::read_line(r, 1024)
   line_res
      | line => io::outf(line, "Echo: {}")
      | --> // Break on EOF or error

41.3.2 Distinguishing EOF, Would-Block, and Errors

#use io

r = io::reader(fd)

0.. @
   chunk = io::read(r, 4096)
   chunk
      | data =>
         io::outf(?data, "Received {} bytes")
      |
         io::reader_would_block(r)
            | --> // Descriptor would block; wait for poll/epoll readiness
         io::reader_eof(r)
            |
               io::out("Clean EOF reached")
               -->
         // Unhandled error (e.g. EBADF, EIO)
         io::errf(io::reader_err(r), "Read failed with errno: {}")
         -->

41.3.3 Reading with unwrap-or-abort (!!)

When expecting a mandatory header or fixed payload where absence represents an unrecoverable failure:

#use io

r = io::reader(fd)
header = io::read_line(r, 256)!! // Aborts with stack trace if EOF or error reached
io::out("Received header: " + header)