1 use async_task::{Builder, Runnable};
2 use flume::unbounded;
3 use smol::future;
4
5 use std::sync::atomic::{AtomicUsize, Ordering};
6
7 #[test]
metadata_use_case()8 fn metadata_use_case() {
9 // Each future has a counter that is incremented every time it is scheduled.
10 let (sender, receiver) = unbounded::<Runnable<AtomicUsize>>();
11 let schedule = move |runnable: Runnable<AtomicUsize>| {
12 runnable.metadata().fetch_add(1, Ordering::SeqCst);
13 sender.send(runnable).ok();
14 };
15
16 async fn my_future(counter: &AtomicUsize) {
17 loop {
18 // Loop until we've been scheduled five times.
19 let count = counter.load(Ordering::SeqCst);
20 if count < 5 {
21 // Make sure that we are immediately scheduled again.
22 future::yield_now().await;
23 continue;
24 }
25
26 // We've been scheduled five times, so we're done.
27 break;
28 }
29 }
30
31 let make_task = || {
32 // SAFETY: We are spawning a non-'static future, so we need to use the unsafe API.
33 // The borrowed variables, in this case the metadata, are guaranteed to outlive the runnable.
34 let (runnable, task) = unsafe {
35 Builder::new()
36 .metadata(AtomicUsize::new(0))
37 .spawn_unchecked(my_future, schedule.clone())
38 };
39
40 runnable.schedule();
41 task
42 };
43
44 // Make tasks.
45 let t1 = make_task();
46 let t2 = make_task();
47
48 // Run the tasks.
49 while let Ok(runnable) = receiver.try_recv() {
50 runnable.run();
51 }
52
53 // Unwrap the tasks.
54 smol::future::block_on(async move {
55 t1.await;
56 t2.await;
57 });
58 }
59