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

Vec

Vec<T> is a replicated, ordered, index-addressable sequence. Internally it is backed by im::Vector<T>, which provides efficient push/pop at both ends and O(log n) random access.

Construction

use mosaik::collections::{Vec, StoreId, SyncConfig};

// Writer — can read and write
let vec = Vec::<String>::writer(&network, StoreId::from("events"));

// Writer with custom sync config
let vec = Vec::<String>::writer_with_config(&network, store_id, config);

// Reader — read-only, deprioritized for leadership
let vec = Vec::<String>::reader(&network, store_id);

// Reader with custom sync config
let vec = Vec::<String>::reader_with_config(&network, store_id, config);

// Aliases: new() == writer(), new_with_config() == writer_with_config()
let vec = Vec::<String>::new(&network, store_id);

Read operations

Available on both writers and readers. Reads operate on the local committed state and never touch the network.

MethodTimeDescription
len() -> usizeO(1)Number of elements
is_empty() -> boolO(1)Whether the vector is empty
get(u64) -> Option<T>O(log n)Get element at index
front() -> Option<T>O(log n)First element
head() -> Option<T>O(log n)Alias for front()
back() -> Option<T>O(log n)Last element
last() -> Option<T>O(log n)Alias for back()
contains(&T) -> boolO(n)Test if a value is in the vector
index_of(&T) -> Option<u64>O(n)Find the index of a value
iter() -> impl Iterator<Item = T>O(1)*Iterate over all elements
version() -> VersionO(1)Current committed state version
when() -> &WhenO(1)Access the state observer

* Iterator creation is O(1) due to structural sharing; full traversal is O(n).

// Random access
if let Some(event) = vec.get(0) {
    println!("First event: {event}");
}

// Peek at ends
let newest = vec.back();
let oldest = vec.front();

// Linear search
if let Some(idx) = vec.index_of(&"restart".into()) {
    println!("Found restart at index {idx}");
}

Write operations

Only available on VecWriter<T>. All writes go through Raft consensus.

MethodTimeDescription
push_back(T) -> Result<Version, Error<T>>O(1)*Append to end
push_front(T) -> Result<Version, Error<T>>O(1)*Prepend to start
insert(u64, T) -> Result<Version, Error<T>>O(log n)Insert at index, shifting elements right
extend(impl IntoIterator<Item = T>) -> Result<Version, Error<Vec<T>>>O(k)*Batch append
pop_back() -> Result<Version, Error<()>>O(1)*Remove last element
pop_front() -> Result<Version, Error<()>>O(1)*Remove first element
remove(u64) -> Result<Version, Error<u64>>O(log n)Remove at index, shifting elements left
swap(u64, u64) -> Result<Version, Error<()>>O(log n)Swap two elements
truncate(usize) -> Result<Version, Error<()>>O(log n)Keep only the first n elements
clear() -> Result<Version, Error<()>>O(1)Remove all elements

* Amortized time complexity.

// Append
let v = vec.push_back("event-1".into()).await?;

// Prepend
vec.push_front("event-0".into()).await?;

// Batch append
let v = vec.extend(["a".into(), "b".into(), "c".into()]).await?;

// Random insert
vec.insert(2, "inserted".into()).await?;

// Remove from ends
vec.pop_back().await?;
vec.pop_front().await?;

// Remove at index
vec.remove(0).await?;

// Swap positions
vec.swap(0, 1).await?;

// Truncate and clear
vec.truncate(10).await?;
vec.clear().await?;

Error handling

Writes return the failed value on Error::Offline so you can retry:

match vec.push_back(item).await {
    Ok(version) => {
        vec.when().reaches(version).await;
    }
    Err(Error::Offline(item)) => {
        // Retry with the same item later
    }
    Err(Error::NetworkDown) => {
        // Permanent failure
    }
}

Status & observation

// Wait until online
vec.when().online().await;

// Wait for a specific committed version
let v = vec.push_back("x".into()).await?;
vec.when().reaches(v).await;

// Wait for any update
vec.when().updated().await;

// React to going offline
vec.when().offline().await;

Group identity

The group key for a Vec<T> is derived from:

UniqueId::from("mosaik_collections_vec")
    .derive(store_id)
    .derive(type_name::<T>())

Two vectors with the same StoreId but different element types will be in separate consensus groups.