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

Collections: Vec, Box, arrays, bytes

After this page you can pick the right container and use it: Vec for lists of scalars, Box for one boxed scalar, [u8; N] for a small fixed byte block, and Bytes for a byte buffer you build.

You haveUse
A list of numbers, bools, or charsVec<T>
One scalar that must live behind an ownerBox<T>
A few known bytes[u8; N]
Bytes you fill inBytes
Textstring, see Ownership

Every call spells its element type, such as vec_push<i64>. T is one of the eight Copy scalars: i64, i32, u8, usize, char, f32, f64, bool. All capacities are bounded.

Build and read a vector

module app.stats;

@id("stats.sum")
fn sum(readings: borrow Vec<i64>) -> i64
{
    let length = vec_len<i64>(readings);
    let mut position = 0usize;
    let mut total = 0;
    while position < length {
        total = total + vec_get<i64>(readings, position);
        position = position + 1usize;
        position < length
    }
    total
}

@id("app.main")
fn main() -> i64
{
    let mut building = vec_with_capacity<i64>(3usize);
    building = vec_push<i64>(building, 2);
    building = vec_push<i64>(building, 3);
    building = vec_push<i64>(building, 0);
    let readings = building;
    sum(readings)
}

Mutators take the vector and return the next one, so you always assign the result back: building = vec_push<i64>(building, 2);. Build with let mut, then move the finished vector into an immutable binding to traverse it.

CallResult
vec_with_capacity<T>(n)An empty vector with room for n items.
vec_push<T>(v, x)The vector with x added.
vec_set<T>(v, i, x)The vector with item i replaced.
vec_clear<T>(v)The emptied vector.
vec_reserve_exact<T>(v, extra)The vector with room for extra more items.
vec_len<T>(v)The length as a usize. Reads only.
vec_get<T>(v, i)A copy of item i. Reads only.
vec_into_iter<T>(v)An Iter<T> that consumes the vector, see Loops.

Pushing past the capacity stops the program (semaprax.vec.v1 status 1, “vec_push beyond capacity”), and so does an index past the length (status 2, “vector index out of bounds”). Reserve enough room first. A for loop avoids the index bookkeeping: see Loops.

In a Project, Vec needs the owned-data-api.v1 profile and std.collections = "^0.1.0". See Profiles.

Keep a scalar in a Box

module app.boxed;

@id("app.main")
fn main() -> i64
{
    let boxed = box_new<i64>(7);
    let peek = box_get<i64>(boxed);
    box_into_inner<i64>(boxed)
}

box_new<T> makes a uniquely owned Box<T>. box_get<T> copies the value out through a borrow. box_into_inner<T> consumes the box. These three names select the compiler’s box. A record you declare yourself as record Box<T> is an ordinary inline record. The box holds one Copy scalar only, with no shared ownership. See Owned Bounded Box v1.

Use a fixed byte array

[97u8, 98u8] has type [u8; 2]. An array literal holds bytes only. A list of i64 is a Vec<i64>, not [1, 2, 3] (SPX-T262). There is no a[0] (SPX-P106). Borrow a view and read with byte_get, which returns an Option<u8> so you handle the missing case:

module app.lookup;

@id("app.main")
fn main() -> i64
{
    let sample = [97u8, 98u8];
    let view = array_as_slice(sample);
    match byte_get(view, 0usize) { Option::Some { value: b } => if b == 97u8 { 0 } else { 1 }, Option::None {} => 2, }
}

Bytes, slices, and strings

TypeOwns its data?Get one fromTurn it into
stringYesA literal, string_concat, string_from_*string_as_str(binding) gives str
strNostring_as_str, arg_utf8str_as_bytes(view) gives Slice<u8>
BytesYesbytes_zeroed + bytes_set, bytes_copy, stdin_readbytes_as_slice(binding) gives Slice<u8>
Slice<u8>Nostr_as_bytes, array_as_slice, bytes_as_slicebyte_len, byte_get, byte_range, stdout_write

A slice is a view. It borrows and never owns. Each conversion takes a named let binding, not a literal or a call result.

Work with text

CallDoes
string_concat(a, b)A new string. Consumes both.
string_len(s), string_len_chars(s)Length in bytes, in Unicode scalars.
string_is_empty(s)true when the length is 0.
string_starts_with(s, p), string_contains(s, p)Search.
string_from_char(c), string_from_i64(n), string_from_usize(n)Render a value as text.
str_len_bytes(v), str_is_empty(v), str_starts_with(v, p), str_contains(v, p)The same reads on a borrowed str.

== compares string contents. These names are reserved: declaring your own string_len is SPX-S113. The full signatures are in Built-in functions.

Exact rules: Owned Bounded Vec v1, v2, String Operations v1, Portable Indexed Byte Data v1.