Skip to main content

select

Macro select 

Source
macro_rules! select {
    (biased;) => { ... };
    (biased; $($branches:tt)+) => { ... };
    () => { ... };
    ($($branches:tt)+) => { ... };
}
Expand description

Waits on several branches at once and runs the handler of the first to finish, dropping the others.

Each branch is <pattern> = <future> (, if <precondition>)? => <handler>, with commas between the branches (optional after a block handler), and an else => <expression> branch may come last. select!:

  1. Evaluates every precondition; a branch whose precondition is false is disabled.
  2. Evaluates every future expression (of disabled branches too), each an IntoFuture.
  3. Polls the futures of the enabled branches, starting at a random one so no branch is favoured, or in the order written after biased;.
  4. When a future finishes, its branch is disabled. If the output matches the branch’s pattern, the other futures are dropped and the handler runs with the pattern’s bindings; if not, the output is dropped and the other branches go on.
  5. When every branch is disabled, the else expression is the value.

The value of select! is the value of the handler that ran, so every handler and else has the same type. A select! takes at most 64 branches.

§Panics

When every branch is disabled and there is no else branch.

§Examples

use nuclei::sync::mpsc;

let (tx, mut numbers) = mpsc::unbounded_channel::<u32>();
let (tick_tx, mut ticks) = mpsc::unbounded_channel::<()>();
tx.send(1).unwrap();
tx.send(2).unwrap();
tick_tx.send(()).unwrap();
drop((tx, tick_tx));
let (mut seen, mut ticked) = (Vec::new(), 0);
// Each closed channel gives `None`, which disables its branch; once
// both are closed, `else` ends the loop.
loop {
    nuclei::select! {
        Some(n) = numbers.recv() => seen.push(n),
        Some(()) = ticks.recv() => ticked += 1,
        else => break,
    }
}
assert_eq!(seen, [1, 2]);
assert_eq!(ticked, 1);

Patterns bind as written, mut, ref and & included, in every edition:

ⓘ
let label = String::from("one");
let n = nuclei::select! {
    (mut n, ref name) = async { (1u32, &label) } => {
        n += name.len() as u32;
        n
    }
};
assert_eq!(n, 4);