__sliced__

Macro __sliced__ 

Source
macro_rules! __sliced__ {
    ($($tt:tt)*) => { ... };
}
Expand description

Transforms a live collection with a computation relying on a slice of another live collection. This is useful for reading a snapshot of an asynchronously updated collection while processing another collection, such as joining a stream with the latest values from a singleton.

§Syntax

The sliced! macro takes in a closure-like syntax specifying the live collections to be sliced and the body of the transformation. Each use statement indicates a live collection to be sliced, along with a non-determinism explanation. Optionally, a style can be specified to control how the live collection is sliced (e.g., atomically). All use statements must appear before the body.

let stream = sliced! {
    let name1 = use(collection1, nondet!(/** explanation */));
    let name2 = use::atomic(collection2, nondet!(/** explanation */));

    // arbitrary statements can follow
    let intermediate = name1.map(...);
    intermediate.cross_singleton(name2)
};

§Stateful Computations

The sliced! macro also supports stateful computations across iterations using let mut bindings with use::state or use::state_null. These create cycles that persist values between iterations.

  • use::state(|l| initial): Creates a cycle with an initial value. The closure receives the slice location and returns the initial state for the first iteration.
  • use::state_null::<Type>(): Creates a cycle that starts as null/empty on the first iteration.

The mutable binding can be reassigned in the body, and the final value will be passed to the next iteration.

let counter_stream = sliced! {
    let batch = use(input_stream, nondet!(/** explanation */));
    let mut counter = use::state(|l| l.singleton(q!(0)));

    // Increment counter by the number of items in this batch
    let new_count = counter.clone().zip(batch.count())
        .map(q!(|(old, add)| old + add));
    counter = new_count.clone();
    new_count.into_stream()
};