The current prelude represents byte data with ordinary sequence types:
[]byteis an owned growableList[byte];[..]byteis a borrowedSlice[byte];Bytesis the read-only byte protocol;Bufferextends it with builder operations.
There is no installed nominal bytes or Buffer struct from the old design.
Owned buffers
mut output: []byte = List.with_capacity[byte](128)
output.append(65u8)
output.append(66u8)A byte list supports normal list operations plus the Buffer contract:
append, clear, append_int, append_float, append_all, and
append_string.
mut output: []byte = []
output.append_string("count=")
output.append_int(42)Builder methods update the mutable receiver and grow its backing storage as
needed. clear() resets the length to zero but keeps capacity for reuse.
append_int and append_float write decimal ASCII directly into reserved
storage without allocating an intermediate string.
append_all accepts any value implementing Bytes, so an owned buffer can
copy from either another list or a borrowed slice:
mut packet: []byte = []
packet.append_all(header.bytes())
packet.append_all(payload)Borrowed views
Use a slice when a callee only needs to read:
fn checksum(data: [..]byte): int {
return fold_checksum(data)
}Slices can be created from list ranges and passed to file or socket writes without copying:
match packet.slice(4..packet.len()) {
Some(payload) => send(payload)
None => report_short_packet()
}A slice borrows the parent allocation. It cannot grow and does not implement
Buffer. Keep the parent alive and do not retain the raw pointer across a
mutation that can reallocate its storage.
Bytes protocol
Any Bytes value exposes:
| Method | Meaning |
|---|---|
byte_len() |
Encoded length |
byte_ptr() |
Arena-relative pointer to first byte |
byte_is_empty() |
Whether length is zero |
byte_at(index) |
Safe optional lookup |
is_valid_utf8() |
Strict UTF-8 validation |
decode_utf8() |
Optional decoded string |
byte_at rejects negative and out-of-range indexes with None.
byte_ptr() is an arena-relative low-level pointer intended for the prelude and
host wrappers. Do not retain it across buffer mutation, scope exit, or
suspension unless the low-level contract explicitly pins the allocation.
Text conversion
Text and bytes are never conflated:
owned: []byte = text.to_bytes()
borrowed: [..]byte = text.bytes()
decoded: string? = owned.decode_utf8()decode_utf8 performs strict Unicode validation and copies valid data into a
fresh string. It rejects overlong encodings, surrogate code points, truncated
sequences, stray continuation bytes, and values above U+10FFFF.
string.bytes() borrows the string’s storage. string.to_bytes() and
decode_utf8() allocate owned results. Choose based on whether ownership must
cross the current scope or asynchronous boundary.
Protocols with replacement semantics should implement that policy explicitly instead of assuming the standard decoder is lossy.
Empty values
Empty byte lists and slices report a length of zero. Their pointer value is an
implementation detail and may be null-like; callers must never dereference
byte_ptr() when byte_len() is zero. The safe protocol methods already
enforce that rule.