Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Data.Bytes

Byte strings: the String/Bytes boundary, and the hex and base64 codecs.

The Bytes type and its representation seam (wire_len, wire_cat, bytes_of_buf, bytes_buf) live in Wire, over the unboxed buffer runtime object (Buf, runtime/prism_buffer.c); this module is the utility layer on top: the length/index/slice/push vocabulary, the UTF-8 conversion seam, the two ASCII encodings, and the byte-level filesystem seam. The utility layer is pure and total, so it threads identically on both backends and participates in the content-addressed story; the two filesystem functions are the deliberate exception (see below).

The String/Bytes boundary

A String is proof-carrying valid UTF-8, so the two directions are asymmetric. string_to_bytes is total: a string’s bytes are always well-formed. Its inverse bytes_to_string must validate, and reports failure honestly as None on ill-formed input rather than lossily repairing it, so a round trip through Bytes never silently mutates a value. Both backends validate identically (the native runtime’s buf_utf8_valid and the interpreter’s UTF-8 check agree byte-for-byte), so the boundary is deterministic.

The encodings

Hex and base64 are written in pure Prism over the buffer builders rather than as runtime primitives: they are O(n) either way and staying in the library keeps both backends in exact agreement for free (no separate C implementation to hold byte-identical). Encoding produces a String of ASCII; decoding validates its input and returns None on any stray character, odd hex length, or malformed base64 group.

Filesystem bytes

read_bytes and write_bytes are the raw-byte counterparts of the prelude’s text read_file/write_file, reading and writing a file’s exact bytes with no UTF-8 interpretation. They stay inside the determinism contract: read_bytes is a FileSystem capability of its own (fs_read_bytes), so its input is captured in the replay trace exactly like a text read; write_bytes is an off-platform output that is not part of the trace, exactly as text writes already are. Bytes are never routed through String (which is proof-carrying UTF-8 and would replace an ill-formed byte with U+FFFD), so an embedded NUL or a lone 0xFF survives a round trip verbatim.

Functions and Values

bytes_length

bytes_length : (Wire.Bytes) -> Int

The number of bytes in a Bytes.

bytes_index

bytes_index : (Wire.Bytes, Int) -> Int

The byte at index i (0-based). Out of range traps, like array indexing.

bytes_empty

bytes_empty : Wire.Bytes

The empty Bytes.

bytes_push

bytes_push : (Wire.Bytes, Int) -> Wire.Bytes

Append one byte (masked into 0..255) to the end of a Bytes. Threaded linearly this is the byte-string builder; a uniquely owned buffer is extended in place (FBIP), a shared one copied.

bytes_slice

bytes_slice : (Wire.Bytes, Int, Int) -> Wire.Bytes

The len bytes starting at start (0-based), as a fresh Bytes. start and len are clamped to the bounds, so an over-long or out-of-range window yields the in-range remainder rather than trapping.

bytes_concat

bytes_concat : (Wire.Bytes, Wire.Bytes) -> Wire.Bytes

Concatenate two byte strings.

bytes_eq

bytes_eq : (Wire.Bytes, Wire.Bytes) -> Bool

Structural equality of two byte strings.

bytes_compare

bytes_compare : (Wire.Bytes, Wire.Bytes) -> Int

Lexicographic comparison (-1/0/1) of two byte strings.

bytes_hash

bytes_hash : (Wire.Bytes) -> String

The blake3 content hash of a byte string as lowercase hex, byte-identical to a String’s blake3 over the same bytes.

string_to_bytes

string_to_bytes : (String) -> Wire.Bytes

Total: a string’s raw UTF-8 bytes as a Bytes.

bytes_to_string

bytes_to_string : (Wire.Bytes) -> Option(String)

Validate the bytes as UTF-8 and, when well-formed, recover the String; None on any ill-formed sequence. The single deterministic conversion seam back from Bytes to String.

hex_encode

hex_encode : (Wire.Bytes) -> String

Lowercase hex encoding: two hex digits per byte.

hex_decode

hex_decode : (String) -> Option(Wire.Bytes)

Decode a hex string to bytes, or None on an odd length or a non-hex character. Upper and lower case digits are both accepted.

base64_encode

base64_encode : (Wire.Bytes) -> String

Standard base64 encoding with = padding.

base64_decode

base64_decode : (String) -> Option(Wire.Bytes)

Decode standard base64 (with = padding) to bytes, or None on a length that is not a multiple of four, a stray character, or misplaced padding.

read_bytes

read_bytes : (String) -> Wire.Bytes ! {FileSystem}

Read the file at path as raw bytes. Carries the FileSystem capability (the fs_read_bytes op the default world handler discharges, via the prelude’s read_file_bytes wrapper) and is replay-recorded like read_file, so a recorded run reproduces the same bytes.

write_bytes

write_bytes : (String, Wire.Bytes) -> Result(Unit, String) ! {IO}

Write bs verbatim to the file at path, returning Ok(()) on success or Err(msg) on failure. The write is the same off-platform output as write_file, over the raw byte buffer so no byte is reinterpreted.