1use core::{pin::Pin, task::Poll};
2
3use crate::{
4 abi,
5 context::{self, PollCall, PollResult},
6};
7
8#[pin_project::pin_project]
10#[repr(transparent)]
11#[must_use = "a task does nothing unless it is driven"]
12pub struct Task<F> {
13 #[pin]
14 state: Option<F>,
15}
16
17impl<F> Task<F> {
18 pub const fn new(fiber: F) -> Self {
19 Self { state: Some(fiber) }
20 }
21 pub(crate) fn poll_with<'d>(
22 self: Pin<&mut Self>,
23 poll: impl FnOnce(Pin<&mut F>) -> PollResult<F::Output>,
24 ) -> PollResult<F::Output>
25 where
26 F: abi::Fiber<'d>,
27 {
28 let mut state = self.project().state;
29 let Some(fiber) = state.as_mut().as_pin_mut() else {
30 return PollResult::Polled(Poll::Pending);
31 };
32 let result = poll(fiber);
33 if matches!(result, PollResult::Polled(Poll::Ready(_))) {
34 state.set(None);
35 }
36 result
37 }
38}
39
40impl<'d, F: abi::Fiber<'d>> abi::Fiber<'d> for Task<F> {
41 type Output = F::Output;
42 fn poll(call: PollCall<'_, '_, 'd, Self>) -> Poll<Self::Output> {
43 let (this, context) = call.into_parts();
44 match this.poll_with(|fiber| {
45 PollResult::Polled(unsafe { context::raw::Live::new(fiber).delegate(context) })
47 }) {
48 PollResult::Polled(poll) => poll,
49 PollResult::Exhausted => Poll::Pending,
50 }
51 }
52}