Reference

std/io/lib

std/io/src/lib.trb

The three streams every process is started with. They are ordinary Source and Sink values (docs/design/STREAMS.md), so everything that reads a file reads standard input, and everything that writes a file writes to the screen:

const total = lines().count().await()?
standardOutput().addLine("{total} lines").await()?

print/printError of the prelude and readLine() here stay as the short form for the common case: a program that prints a line does not want to think about a stream.

fn readLine

fn readLine(): Result<String?, IoError>

The next line of standard input without its line break: Ok(None) at the end of the input, and an IoError for a line whose bytes are not UTF-8.

Standard input comes from outside the program, so its bytes are a property of the data and not a promise the program made: a line that cannot be text is a Result and never a panic (CONCEPT.md, "Error Handling").

Examples

while const Some(line) = readLine()? {
  print line.toUpperCase()
}

fn standardInput

fn standardInput(): Source<Bytes, IoError>

Standard input as a stream of byte chunks, each read on a thread of the blocking pool as it arrives.

fn standardOutput

fn standardOutput(): Sink<Bytes, IoError>

Standard output as a stream of byte chunks. Not buffered: every add goes out. standardOutput().buffered(capacity: 4096) is the form a program that writes a lot of small pieces wants, and it says where the flush is.

fn standardError

fn standardError(): Sink<Bytes, IoError>

Standard error, unbuffered for the reason it is everywhere: a diagnostic that is lost is worse than a slow one.

fn lines

fn lines(): Source<String, IoError>

The lines of standard input, as a stream: the same stage File.lines uses, over the same kind of source.

Examples

const total = lines().count().await()
print total