Skip to main content

moirai_async/executor/
handle.rs

1use crate::executor::result_slot::AsyncResultSlot;
2use moirai_core::TaskId;
3use std::future::Future;
4use std::pin::Pin;
5use std::sync::Arc;
6use std::task::{Context, Poll};
7
8/// A handle to an async task that can be awaited.
9pub struct AsyncHandle<T> {
10    pub(super) task_id: TaskId,
11    pub(super) result_slot: Arc<AsyncResultSlot<T>>,
12}
13
14impl<T> AsyncHandle<T> {
15    /// Return the executor-assigned task identifier.
16    #[must_use]
17    pub fn id(&self) -> TaskId {
18        self.task_id
19    }
20}
21
22impl<T> Future for AsyncHandle<T> {
23    type Output = T;
24
25    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
26        if let Some(value) = self.result_slot.try_take_ready() {
27            return Poll::Ready(value);
28        }
29
30        self.result_slot.register_waker(cx.waker());
31
32        // Re-check is mandatory, not defensive: a `complete` that raced in on the
33        // slot's PENDING->WRITING path does not wake (no waker was registered when
34        // it ran), so this second take is what closes the lost-wakeup window. See
35        // the `result_slot` module docs.
36
37        self.result_slot
38            .try_take_ready()
39            .map_or(Poll::Pending, Poll::Ready)
40    }
41}