Overview
Byte-level I/O operations, CML event-driven reads, streaming conversions, and port adapters.
(import (std ports))
;; Read a 4-byte length header followed by the payload.
(defbjo (read-frame in)
(match (read-bytes in 4)
((Some header) (read-bytes in (frame-length header)))
(None None)))
;; Read available bytes with a 1-second timeout.
(match (sync (choose (read-some-evt in)
(wrap (timeout (seconds 1)) (fun (_) (Ok None)))))
((Ok (Some bytes)) (use bytes))
((Ok None) (log "EOF or stream completed"))
((Err e) (raise e)))
;; In-memory bidirectional pipe for unit testing without network/file I/O.
(match (byte-pipe)
((Tuple in out)
(write-string out "hello\n")
(close-output-port out)
(read-line in))) ; "hello"
An InputPort represents an underlying stream of binary bytes.
Textual functions like read-line and read-char decode UTF-8
data from the port. Binary functions like read-some,
read-bytes, and peek-bytes read raw byte sequences directly.
Both textual and binary operations can be interleaved on the same port.
An OutputPort supports both UTF-8 text (write-string,
write-char) and binary byte arrays (write-bytes!).
Event-based reads in choose. Inbound data read from the
underlying stream is stored in the port’s internal buffer. An event-based
read consumes bytes from this buffer only when its branch wins
synchronization in choose. If another branch synchronizes first,
no bytes are consumed, leaving the buffered bytes available for subsequent
read operations.
Byte-reading operations are available as CML events:
read-some-evt, read-bytes-evt, and eof-evt.
Synchronous wrappers (read-some, read-bytes) synchronize
these events directly.
Draining and streaming. port->list, port->vec,
and port->lines eagerly consume a port until EOF. port->seq
and file->seq provide lazy evaluation sequences.
port->chan offloads reads to a dedicated background fiber that sends
items over a channel.
Stream adapters. Files are opened via prelude functions
open-input-file and open-output-file. .NET Stream
instances can be adapted using stream->input-port and
stream->output-port. Bidirectional network streams are supported
via (std net).
See BjolangRuntime/BjoInputPort.cs for input port implementation
details.
See also: read-some-evt, read-some, read-bytes, peek-bytes, write-bytes!, shutdown!, byte-pipe, port->vec, port->chan
Reference
Types
Stream
type alias ↑ Types
The .NET System.IO.Stream type wrapped by Bjolang ports.
See also: stream->input-port, stream->output-port
Functions
port->list
function ↑ Functions
(: port->list (-> (-?-> InputPort %a) InputPort (List %a)))
(port->list reader p)
Consumes items from a port until EOF, returning them as a list.
reader- Reader function or bjoroutine invoked to read each item.
p- The input port.
- returns
- A list of read items in order of occurrence.
(port->list read-char (open-input-string "abc")) ; (#\\a #\\b #\\c)
The reader is invoked repeatedly while port-eof? returns #f.
The reader must consume input on each invocation to prevent an infinite
loop.
If reader is a bjoroutine, calls suspend cooperatively. If it is
a standard synchronous function, calls block the active thread. The port
is not closed automatically.
See also: port->vec, port->lines, port->seq, port->chan
port->vec
function ↑ Functions
(: port->vec (-> (-?-> InputPort %a) InputPort (Vec %a)))
(port->vec reader p)
Consumes items from a port until EOF, returning them as a vector.
reader- Reader function or bjoroutine invoked to read each item.
p- The input port.
- returns
- A vector containing all read items in order.
Equivalent to port->list, but collects items into an indexed
vector.
See also: port->list, port->lines, port->chan
port->lines
function ↑ Functions
(: port->lines (-> InputPort (#:mode LineMode) (Vec string)))
(port->lines port #:mode Any)
Reads all remaining lines from a port into a list.
port- The input port.
#:mode- Line delimiter mode (defaults to
Any). - returns
- A list of strings containing remaining lines without delimiters.
Reads synchronously using read-line. To suspend cooperatively
within a bjoroutine, use port->vec with a bjoroutine reader.
See also: port->vec, read-line, LineMode
port->seq
function ↑ Functions
(: port->seq (-> (-> InputPort %a) InputPort (Seq %a)))
(port->seq reader p)
Returns a lazy sequence of items read from a port.
reader- Reader function invoked to produce each item.
p- The input port.
- returns
- A lazy sequence that reads from the port as elements are evaluated.
Items are read on demand during sequence iteration, not at sequence creation time. The port is not closed upon completion. Reading mutates port state, so repeated traversals continue from where the previous traversal ended.
Sequence evaluation cannot suspend cooperatively; within a bjoroutine,
use port->vec or port->chan instead.
See also: port->vec, port->chan, file->seq
file->seq
function ↑ Functions
(: file->seq (-> (-> InputPort %a) string (Result Exception (Seq %a))))
(file->seq reader path)
Returns a lazy sequence of items read from a file path.
reader- Reader function invoked on the file's input port.
path- Path to the target file.
- returns
(Ok seq)on success, or(Err e)if the file cannot be opened.
The file is initially opened to verify accessibility and immediately closed. Each sequence iteration opens the file anew, reads from the beginning, and closes it upon reaching EOF.
See also: file-read/seq, port->seq
port->chan
function ↑ Functions
(: port->chan (-> (-bjo-> InputPort %a) InputPort (Tuple (Chan %a) (Promise int))))
(port->chan reader p)
Spawns a fiber that reads items from a port and streams them over a channel.
reader- Bjoroutine reader invoked to read each item.
p- The input port.
- returns
- A tuple containing the output channel and a completion promise holding the count of read items.
- raises
Bjolang.Runtime.ScopeEnded - When invoked outside an ambient structured concurrency scope.
(match (port->chan read-line port)
((Tuple lines done)
(let go ()
(match (chan-next lines done)
((Some line) (handle line) (go))
(None 'finished)))))
The producer fiber executes within the ambient scope. The unbuffered channel ensures backpressure: the worker fiber reads the next item only after the receiver consumes the previous one. The port is not closed automatically.
If the reader throws an exception, the completion promise fails and no further items are emitted.
chan-next
function ↑ Functions
(: chan-next (-bjo-> (Chan %a) (Promise int) (Option %a)))
(chan-next c done)
Fetches the next item from a port->chan stream, or None at EOF.
c- The channel returned by
port->chan. done- The completion promise returned by
port->chan. - returns
(Some item)if an item is available, orNoneif the stream completed.
Synchronizes on both the channel and the completion promise. To check
for errors after None is returned, join the completion promise:
(sync (promise-join done)).
See also: port->chan
read-some-evt
function ↑ Functions
(: read-some-evt (-> InputPort (Event (Result Exception (Option (Array byte))))))
(read-some-evt p)
Returns a CML event that reads available bytes from the port buffer.
p- The input port.
- returns
- An event yielding
(Ok (Some bytes))with at least 1 byte,(Ok None)at EOF, or(Err e)on I/O failure.
First-class CML event. If another branch in choose synchronizes
first, no bytes are consumed and the buffer contents remain intact.
The event is ephemeral: each synchronization evaluates against the current port state, allowing repeated reads in a loop without stale cached results.
See also: read-some, read-bytes-evt, eof-evt
read-bytes-evt
function ↑ Functions
(: read-bytes-evt (-> InputPort int (Event (Result Exception (Option (Array byte))))))
(read-bytes-evt p n)
Returns a CML event that reads exactly n bytes, or remaining bytes at EOF.
p- The input port.
n- Target byte count. Must be at least 1.
- returns
- An event yielding
(Ok (Some bytes)),(Ok None)at EOF, or(Err e)on failure. - raises
System.ArgumentOutOfRangeException - When n is less than 1.
If EOF is reached before n bytes are read, any remaining bytes are
yielded as (Some bytes), and the subsequent read yields
None.
See also: read-bytes, read-some-evt
eof-evt
function ↑ Functions
(: eof-evt (-> InputPort (Event Unit)))
(eof-evt p)
Returns a CML event that triggers when a port reaches EOF or encounters an error.
p- The input port.
- returns
- An event enabled when no further bytes can be read.
Triggers when the port buffer is exhausted and no further input can arrive. Useful for detecting peer disconnections in network protocols.
See also: read-some-evt, port-eof?
read-some
function ↑ Functions
(: read-some (-> InputPort (Option (Array byte))))
(read-some p)
Reads available bytes from the port, blocking or suspending until at least one byte arrives.
p- The input port.
- returns
(Some bytes)containing at least 1 byte, orNoneat EOF.- raises
System.IO.IOException - When an underlying stream I/O failure occurs.
Synchronizes on read-some-evt. Suspends cooperatively within a
bjoroutine; blocks the thread in standard synchronous code.
See also: read-some-evt, read-bytes
read-bytes
function ↑ Functions
(: read-bytes (-> InputPort int (Option (Array byte))))
(read-bytes p n)
Reads exactly n bytes, or remaining bytes at EOF.
p- The input port.
n- Number of bytes to read. Must be at least 1.
- returns
(Some bytes)(shorter than n only at EOF), orNoneif already at EOF.- raises
System.ArgumentOutOfRangeException - When n is less than 1.
- raises
System.IO.IOException - When an underlying stream I/O failure occurs.
See also: read-bytes-evt, read-some, peek-bytes
peek-bytes
function ↑ Functions
(: peek-bytes (-> InputPort int int (Option (Array byte))))
(peek-bytes p skip count)
Inspects bytes ahead of the port cursor without consuming them.
p- The input port.
skip- Number of bytes to skip before peeking. Must be non-negative.
count- Number of bytes to peek. Must be non-negative.
- returns
(Some bytes)(shorter than count at EOF), orNoneif EOF occurs before skip.- raises
System.ArgumentOutOfRangeException - When skip or count is negative.
- raises
System.IO.IOException - When the stream fails and the buffer is empty.
;; Inspect magic bytes before choosing a decompression strategy:
(match (peek-bytes in 0 2)
((Some magic) (if (gzip-magic? magic) (inflate in) (plain in)))
(None (empty)))
Buffers data until the requested range is satisfied or EOF is reached.
Bytes remain in the port buffer and can subsequently be consumed by
read-bytes or textual readers.
See also: read-bytes, reencode-input-port
write-bytes!
function ↑ Functions
(: write-bytes! (-> OutputPort (Array byte) void))
(write-bytes! p bytes)
Writes a byte array to an output port.
p- The output port.
bytes- Byte array to write.
- raises
System.InvalidOperationException - When called after shutdown! has closed the output side.
Output ports are buffered. Writes that fill the buffer trigger a flush to the underlying stream, suspending cooperatively in fibers or blocking in synchronous functions.
See also: flush-port, shutdown!, write-string
shutdown!
function ↑ Functions
(: shutdown! (-> OutputPort void))
(shutdown! p)
Shuts down the write half of a duplex port while keeping the read half open.
p- The output port.
Flushes buffered data and transmits a shutdown signal (e.g. TCP FIN or
pipe EOF) to the peer. Subsequent write operations throw
InvalidOperationException. The port must still be closed with
close-output-port to release underlying system handles.
See also: write-bytes!, flush-port, byte-pipe
limited
function ↑ Functions
(: limited (-> InputPort int InputPort))
(limited p n)
Wraps an input port to read at most n bytes before reporting EOF.
p- The source input port.
n- Maximum number of bytes to read. Must be non-negative.
- returns
- A new limited input port reading through p.
- raises
System.ArgumentOutOfRangeException - When n is negative.
;; Read a fixed-length HTTP body as text lines without consuming trailing data:
(port->lines (limited conn content-length))
Reads through the underlying port’s buffer without skipping or duplicating data. Closing the limited port does not close the underlying source port.
See also: byte-pipe, reencode-input-port
byte-pipe
function ↑ Functions
(: byte-pipe (-> (Tuple InputPort OutputPort)))
(byte-pipe)
Creates an in-memory duplex byte pipe.
- returns
- A pair of (input-port, output-port).
An unbounded in-memory pipe suitable for testing and internal message buffering. Writes do not block. Closing or shutting down the output port signals EOF to the input port once buffered bytes are drained.
See also: limited, shutdown!, stream->input-port
stream->input-port
function ↑ Functions
(: stream->input-port (-> Stream InputPort))
(stream->input-port s)
Wraps a .NET Stream in a Bjolang input port.
s- The .NET Stream instance.
- returns
- A new input port reading from s.
- raises
Bjolang.Runtime.ScopeEnded - When called without an ambient structured concurrency scope.
The port takes ownership of the stream. Closing the port or exiting the ambient concurrency scope disposes the underlying stream.
See also: stream->output-port
stream->output-port
function ↑ Functions
(: stream->output-port (-> Stream OutputPort))
(stream->output-port s)
Wraps a .NET Stream in a Bjolang output port.
s- The .NET Stream instance.
- returns
- A new output port writing to s.
- raises
Bjolang.Runtime.ScopeEnded - When called without an ambient structured concurrency scope.
The port takes ownership of the stream. Closing the port or exiting the ambient concurrency scope flushes and disposes the underlying stream.
See also: stream->input-port
reencode-input-port
function ↑ Functions
(: reencode-input-port (-> InputPort Encoding InputPort))
(reencode-input-port p encoding)
Wraps an input port to transcode bytes from a specified encoding into UTF-8.
p- The source input port.
encoding- Source text encoding from
(text encodings). - returns
- A new input port yielding UTF-8 bytes.
(import (only (text encodings) windows-1252))
(read-line (reencode-input-port in windows-1252))
Transcodes input on the fly into UTF-8. Unrecognized byte sequences are replaced with U+FFFD. Closing the re-encoded port does not close the underlying source port.
See also: reencode-output-port, peek-bytes, Encoding
reencode-output-port
function ↑ Functions
(: reencode-output-port (-> OutputPort Encoding OutputPort))
(reencode-output-port p encoding)
Wraps an output port to transcode outgoing UTF-8 bytes into a specified target encoding.
p- The destination output port.
encoding- Target text encoding from
(text encodings). - returns
- A new output port accepting UTF-8 bytes.
Transcodes UTF-8 input into the target encoding before writing to p. Characters not representable in the target encoding are replaced with fallback characters. Closing the wrapped port flushes remaining data to p while leaving p open.
See also: reencode-input-port, Encoding