dope-manifold 0.36.0

Owned application and service composition for dope
use std::{mem, pin};

use dope_core::driver::{
    self,
    receive::Stale,
    route::Identity,
    schedule::{self, ready},
};
use dope_net::{
    link::{
        event,
        pool::recv::{arrival, delivery, input, reserve::Choice},
    },
    wire,
};

use crate::app::receive::ingress::{self, Admission, Dispatch, Replay};

pub(crate) struct Single<'a, 'c, 'd> {
    driver: &'a mut driver::Context<'c, 'd>,
    turn: schedule::Turn<'a, 'd>,
}

impl<'a, 'c: 'a, 'd: 'a + 'c> Admission<'a, 'c, 'd> for Single<'a, 'c, 'd> {
    fn fresh(
        turn: schedule::Turn<'a, 'd>,
        driver: &'a mut driver::Context<'c, 'd>,
    ) -> schedule::Capacity<Self> {
        schedule::Capacity::Available(Self { driver, turn })
    }

    fn replay(
        replay: Replay,
        ready: ready::Key<'d>,
        turn: schedule::Turn<'a, 'd>,
        driver: &'a mut driver::Context<'c, 'd>,
    ) -> schedule::Capacity<Self> {
        if matches!(replay, Replay::Waiting) {
            let Some(permit) = turn.app().permit() else {
                driver.driver_ref().ready().activate(ready);
                return schedule::Capacity::Exhausted;
            };
            return permit.run(|| Self::fresh(turn, driver));
        }
        Self::fresh(turn, driver)
    }
}

impl<'a, 'c, 'd> Single<'a, 'c, 'd> {
    pub(in crate::app::receive::ingress) fn drive<'p, 'w, ID: Identity + 'd, W, M, P, A, C>(
        self,
        mut policy: pin::Pin<&mut P>,
        data: A,
        emit: impl FnOnce(
            delivery::Data<'_, 'w, 'd, ID, W, M::Kind, input::Receipt<W, M>>,
        ) -> event::DispatchRecv<'d, ID, C>,
        apply: impl FnOnce(
            pin::Pin<&mut P>,
            event::DispatchRecv<'d, ID, C>,
            schedule::Turn<'_, 'd>,
            &mut driver::Context<'_, 'd>,
        ),
    ) where
        'c: 'a,
        'd: 'a + 'c + 'w + 'p,
        W: wire::Spec + 'w + 'd,
        M: Dispatch<W>,
        P: ingress::Policy<'p, 'w, 'd, ID, Wire = W, Input = M>,
        M::Reserve: Choice<W, M::Ingress>,
        A: arrival::Arrival<'d, input::Receipt<W, M>, Observed = event::Data<'d>>,
    {
        let plan = P::reserve(policy.as_mut(), data, self.driver.region_token()).map(emit);
        let next = match plan {
            event::Reservation::Ready(next) => next,
            event::Reservation::Control(next) => event::DispatchRecv::Control(next),
            event::Reservation::Parked(parked) => {
                let (driver, turn) = self.into();
                ingress::apply_parked(policy, parked, turn, driver);
                return;
            }
            event::Reservation::Stale(Stale) | event::Reservation::Drop => return,
        };
        let (driver, turn) = self.into();
        apply(policy.as_mut(), next, turn, driver);
    }
}

impl<'a, 'c, 'd> From<Single<'a, 'c, 'd>>
    for (&'a mut driver::Context<'c, 'd>, schedule::Turn<'a, 'd>)
{
    fn from(work: Single<'a, 'c, 'd>) -> Self {
        (work.driver, work.turn)
    }
}

const _: () = {
    assert!(mem::size_of::<Single<'static, 'static, 'static>>() == 2 * mem::size_of::<usize>());
    assert!(mem::align_of::<Single<'static, 'static, 'static>>() == mem::align_of::<usize>());
};