use async_task::{Builder, Runnable};
use flume::unbounded;
use smol::future;
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::sync::Arc;
struct DropFlag(Arc<AtomicBool>);
impl Drop for DropFlag {
fn drop(&mut self) {
self.0.store(true, Ordering::SeqCst);
}
}
#[test]
fn metadata_drop_waits_for_the_last_waker() {
let dropped = Arc::new(AtomicBool::new(false));
let (runnable, task) = Builder::new()
.metadata(DropFlag(dropped.clone()))
.spawn(|_| async {}, |_| {});
let waker = runnable.waker();
drop(runnable);
drop(task);
assert!(!dropped.load(Ordering::SeqCst));
drop(waker);
assert!(dropped.load(Ordering::SeqCst));
}
#[test]
fn metadata_use_case() {
let (sender, receiver) = unbounded::<Runnable<AtomicUsize>>();
let schedule = move |runnable: Runnable<AtomicUsize>| {
runnable.metadata().fetch_add(1, Ordering::SeqCst);
sender.send(runnable).ok();
};
async fn my_future(counter: &AtomicUsize) {
loop {
let count = counter.load(Ordering::SeqCst);
if count < 5 {
future::yield_now().await;
continue;
}
break;
}
}
let make_task = || {
let (runnable, task) = unsafe {
Builder::new()
.metadata(AtomicUsize::new(0))
.spawn_unchecked(my_future, schedule.clone())
};
runnable.schedule();
task
};
let t1 = make_task();
let t2 = make_task();
while let Ok(runnable) = receiver.try_recv() {
runnable.run();
}
smol::future::block_on(async move {
t1.await;
t2.await;
});
}