to give you an idea of what the syntax looks like:
// regular async function that waits `ticks` ticks
async fn wait_ticks(ticks: i32) {
for _ in 0..ticks {
future::yield_now().await;
}
}
// PREEMPTIBLE async function that increments an &mut i32
#[preemptible(data)]
async fn increment_n_times(data: &mut i32, times: i32) {
for i in 0..times {
assert_eq!(*data, i);
*data += 1;
future::yield_now().await;
}
}
// another preemptible async function that sets a mutable i32
#[preemptible(data)]
async fn set(data: &mut i32, val: i32) {
*data = val;
}
// this is needed for the test case to pass
#[preemptible(data)]
async fn data_assert(data: &mut i32, cond: fn(i32) -> bool) {
assert!(cond(*data));
}
// a RevocableCell called `data` is created with the initial value 0
let data = RevocableCell::new(0, "test data");
let wait_5_then_reset = async || {
wait_ticks(5).await;
set(&data, 0).await?;
data_assert(&data, |x| x == 0).await?;
Ok(())
};
let (a, b) = future::zip(wait_5_then_reset(), increment_n_times(&data, 100)).await;
assert!(a.is_ok()); // a ran to completion
assert!(b.is_err()); // b got cancelled by set after 5 ticks of a
// data got reset to 0 in a
data_assert(&data, |x| x == 0).await.unwrap();
let res = future::try_zip(wait_5_then_reset(), increment_n_times(&data, 100)).await;
assert!(res.is_err()); // a preempted b, cancelling both since they are joined