|  | use async_task::{Builder, Runnable}; | 
|  | use flume::unbounded; | 
|  | use smol::future; | 
|  |  | 
|  | use std::sync::atomic::{AtomicUsize, Ordering}; | 
|  |  | 
|  | #[test] | 
|  | fn metadata_use_case() { | 
|  | // Each future has a counter that is incremented every time it is scheduled. | 
|  | 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 { | 
|  | // Loop until we've been scheduled five times. | 
|  | let count = counter.load(Ordering::SeqCst); | 
|  | if count < 5 { | 
|  | // Make sure that we are immediately scheduled again. | 
|  | future::yield_now().await; | 
|  | continue; | 
|  | } | 
|  |  | 
|  | // We've been scheduled five times, so we're done. | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | let make_task = || { | 
|  | // SAFETY: We are spawning a non-'static future, so we need to use the unsafe API. | 
|  | // The borrowed variables, in this case the metadata, are guaranteed to outlive the runnable. | 
|  | let (runnable, task) = unsafe { | 
|  | Builder::new() | 
|  | .metadata(AtomicUsize::new(0)) | 
|  | .spawn_unchecked(my_future, schedule.clone()) | 
|  | }; | 
|  |  | 
|  | runnable.schedule(); | 
|  | task | 
|  | }; | 
|  |  | 
|  | // Make tasks. | 
|  | let t1 = make_task(); | 
|  | let t2 = make_task(); | 
|  |  | 
|  | // Run the tasks. | 
|  | while let Ok(runnable) = receiver.try_recv() { | 
|  | runnable.run(); | 
|  | } | 
|  |  | 
|  | // Unwrap the tasks. | 
|  | smol::future::block_on(async move { | 
|  | t1.await; | 
|  | t2.await; | 
|  | }); | 
|  | } |