macro_rules! inline { ($($tt:tt)*) => { ... }; }
Expand description
The inline!
macro provides an inlined variant of the select! macro.
Instead of awaiting directly it evaluates to an instance of the Select or StaticSelect allowing for more efficient multiplexing and complex control flow.
When combined with the static;
option it performs the least amount of
magic possible to multiplex multiple asynchronous operations making it
suitable for efficient and custom abstractions.
Branches and state
The inline!
macro differs from select! in that it allows for retaining
information on which branches have been disabled due to the future
completing without having to rely on a [branch condition].
In contrast to select! it does not allow for performing additional
asynchronous operations in the branches, nor affecting the control flow of
the surrounding context like through break
.
The following would not compile, since the break
below is not evaluated in
the context of the loop:
let s1 = std::future::ready(());
loop {
selectme::inline! {
() = s1 => 1,
else => break,
}.await;
}
While this seems like it would make it less useful, instead it means that it can efficiently perform inline common inline operations like timeouts.
use std::time::Duration;
use tokio::time;
async fn async_operation() -> u32 {
// work here
}
let output = selectme::inline! {
output = async_operation() => Some(output),
() = time::sleep(Duration::from_secs(5)) => None,
}.await;
match output {
Some(output) => {
assert_eq!(output, 42);
}
None => {
panic!("operation timed out!")
}
}
Static selects
The inline!
macro can also make use of the static;
option, which allows
the select that is generated to be named. This can be useful if you want to
incorporate selection-like behaviour into another future.
Note that this option is not supported in select!.
use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};
use std::time::Duration;
use pin_project::pin_project;
use selectme::{Random, StaticSelect};
use tokio::time::{self, Sleep};
#[pin_project]
struct MyFuture {
#[pin]
select: StaticSelect<u8, (Sleep, Sleep), Random, Option<u32>>,
}
impl Future for MyFuture {
type Output = Option<u32>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.project();
this.select.poll_next(cx)
}
}
let s1 = time::sleep(Duration::from_millis(100));
let s2 = time::sleep(Duration::from_millis(200));
let my_future = MyFuture {
select: selectme::inline! {
static;
() = s1 => Some(1),
_ = s2 => Some(2),
else => None,
}
};
assert_eq!(my_future.await, Some(1));
Examples
use std::time::Duration;
use tokio::time;
let s1 = time::sleep(Duration::from_millis(100));
let s2 = time::sleep(Duration::from_millis(200));
let output = selectme::inline! {
() = s1 => Some(1),
_ = s2 => Some(2),
else => None,
};
tokio::pin!(output);
let mut values = Vec::new();
while let Some(output) = output.as_mut().next().await {
values.push(output);
}
assert_eq!(values, &[1, 2]);