dope-fiber 0.11.0

The manifold runtime
Documentation
use core::pin::Pin;
use std::io;

use dope::driver::ready::ReadySlot;
use dope::driver::token::{Epoch, SlotIndex, Token, kind};
use dope::runtime::__private::RootTask;
use dope::{DriverContext, DriverRef};
use pin_project::pin_project;

use crate::{Context, Fiber};

#[pin_project]
pub struct OneShot<'d, F>
where
    F: Fiber<'d>,
{
    #[pin]
    fiber: Option<F>,
    output: Option<F::Output>,
    #[pin]
    slot: ReadySlot<'d>,
    target: Token,
}

impl<'d, F> OneShot<'d, F>
where
    F: Fiber<'d>,
{
    pub fn new(fiber: F, route: u8, driver: DriverRef<'d>) -> io::Result<Self> {
        let target = Token::new(route, SlotIndex::new(0), Epoch::INITIAL).with_kind(kind::ONE_SHOT);
        Ok(Self {
            fiber: Some(fiber),
            output: None,
            slot: driver.make_ready_slot(target)?,
            target,
        })
    }

    pub fn target(&self) -> Token {
        self.target
    }

    pub fn is_done(&self) -> bool {
        self.fiber.is_none()
    }

    pub fn take_output(self: Pin<&mut Self>) -> Option<F::Output> {
        self.project().output.take()
    }

    pub fn pre_park(self: Pin<&mut Self>, driver: &mut DriverContext<'_, 'd>) {
        let this = unsafe { self.get_unchecked_mut() };
        let slot = unsafe { Pin::new_unchecked(&this.slot) };
        let mut context = core::pin::pin!(Context::from_ready(
            driver.driver_ref(),
            slot.key(),
            driver.reborrow(),
        ));
        let Some(fiber) = this.fiber.as_mut() else {
            return;
        };
        if let core::task::Poll::Ready(output) =
            Fiber::poll(unsafe { Pin::new_unchecked(fiber) }, context.as_mut())
        {
            this.output = Some(output);
            this.fiber = None;
        }
    }
}

impl<'d, F> RootTask<'d, F::Output> for OneShot<'d, F>
where
    F: Fiber<'d>,
{
    fn target(&self) -> Token {
        self.target()
    }

    fn pre_park(self: Pin<&mut Self>, driver: &mut DriverContext<'_, 'd>) {
        self.pre_park(driver);
    }

    fn take_output(self: Pin<&mut Self>) -> Option<F::Output> {
        self.take_output()
    }
}