Skip to main content

moirai_core/task/
future.rs

1use core::future::Future;
2use core::pin::Pin;
3
4use super::id_and_context::TaskContext;
5use super::traits::Task;
6
7/// A future adapter that executes a [`Task`] on first poll.
8///
9/// # Execution semantics
10///
11/// The wrapped task runs **synchronously inside the first `poll` call** on the
12/// polling thread — this adapter does not offload work to an executor, does
13/// not yield mid-task, and never returns `Poll::Pending`. It exists so a
14/// synchronous task can be awaited from async code; the `.await` completes in
15/// one poll, blocking the async worker for the task's full duration. Offload
16/// long-running tasks to a blocking pool instead of awaiting them directly on
17/// an async executor.
18///
19/// # Fused
20///
21/// Like [`core::future::Ready`] and other std-convention one-shot futures,
22/// polling again after completion is a contract violation and panics.
23#[allow(clippy::module_name_repetitions)]
24pub struct TaskFuture<T> {
25    task: Option<T>,
26    context: TaskContext,
27}
28
29impl<T> TaskFuture<T>
30where
31    T: Task,
32{
33    /// Create a new task future.
34    pub fn new(task: T, context: TaskContext) -> Self {
35        Self {
36            task: Some(task),
37            context,
38        }
39    }
40
41    /// Get the task context.
42    pub fn context(&self) -> &TaskContext {
43        &self.context
44    }
45}
46
47impl<T> Future for TaskFuture<T>
48where
49    T: Task + Unpin,
50{
51    type Output = T::Output;
52
53    /// Executes the task synchronously and returns `Poll::Ready` on the first
54    /// call; see the type-level docs for the blocking semantics.
55    ///
56    /// # Panics
57    /// Panics if polled again after it has returned `Poll::Ready` (fused
58    /// one-shot contract; a completed future has no result to hand out and no
59    /// waker-based path by which `Pending` could ever resolve).
60    fn poll(
61        self: Pin<&mut Self>,
62        _cx: &mut core::task::Context<'_>,
63    ) -> core::task::Poll<Self::Output> {
64        let task = self
65            .get_mut()
66            .task
67            .take()
68            .expect("TaskFuture polled after completion");
69        core::task::Poll::Ready(task.execute())
70    }
71}