Skip to main content

jay_config/
tasks.rs

1//! Tools for async task management.
2
3use std::cell::Cell;
4use std::fmt::Debug;
5use std::fmt::Formatter;
6use std::future::Future;
7use std::pin::Pin;
8use std::rc::Rc;
9use std::task::Context;
10use std::task::Poll;
11use std::task::Waker;
12
13/// Spawns an asynchronous task that will run in the background.
14pub fn spawn<T, F>(f: F) -> JoinHandle<T>
15where
16    T: 'static,
17    F: Future<Output = T> + 'static,
18{
19    let slot = match try_get!() {
20        None => Rc::new(JoinSlot {
21            task_id: 0,
22            slot: Cell::new(None),
23            waker: Cell::new(None),
24        }),
25        Some(c) => c.spawn_task(f),
26    };
27    JoinHandle { slot }
28}
29
30pub(crate) struct JoinSlot<T> {
31    pub task_id: u64,
32    pub slot: Cell<Option<T>>,
33    pub waker: Cell<Option<Waker>>,
34}
35
36/// A handle to join or abort a spawned task.
37///
38/// When the handle is dropped, the task continues to run in the background.
39pub struct JoinHandle<T> {
40    slot: Rc<JoinSlot<T>>,
41}
42
43impl<T> Debug for JoinHandle<T> {
44    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
45        f.debug_struct("JoinHandle")
46            .field("task_id", &self.slot.task_id)
47            .finish_non_exhaustive()
48    }
49}
50
51impl<T> Unpin for JoinHandle<T> {}
52
53impl<T> JoinHandle<T> {
54    /// Aborts the task immediately.
55    pub fn abort(self) {
56        get!().abort_task(self.slot.task_id);
57    }
58}
59
60impl<T> Future for JoinHandle<T> {
61    type Output = T;
62
63    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
64        if let Some(t) = self.slot.slot.take() {
65            return Poll::Ready(t);
66        }
67        self.slot.waker.set(Some(cx.waker().clone()));
68        Poll::Pending
69    }
70}