dope-manifold 0.22.0

Owned application and service composition for dope
Documentation
use std::pin;

use dope_core::driver::{
    self, retained,
    route::Identity,
    schedule,
    schedule::{clock, ready::wake},
};
use dope_net::wire;
use o3::mem::quota;

use crate::{
    app::env,
    client::{
        app, attempt,
        conn::engine::{self, liveness, ops::opens},
        side::mode::Mode,
    },
};

#[derive(Clone, Copy, Eq, PartialEq)]
pub(in crate::client) enum Source {
    Idle,
    Deferred,
}

#[derive(Clone, Copy, Eq, PartialEq)]
pub(in crate::client) enum Retry {
    Ready,
    Pending,
}

pub(in crate::client) struct Dial<'a, 'p, 'w, 'd: 'w, ID: Identity + 'd, A, S, E, X>
where
    A: app::Lifecycle<'w, 'd, ID> + app::Scheduling<'d, ID>,
    S: attempt::Control<'d, E::Transport, ID>,
    E: env::Spec<Wire = A::Wire>,
    E::Transport: dope_net::Transport,
    X: Mode<'d, ID>,
{
    machine: pin::Pin<&'a mut engine::Machine<'p, 'w, 'd, ID, A, S, E, X>>,
}

impl<'p, 'a, 'w, 'd: 'p + 'w, ID: Identity + 'd, A, S, E, X> Dial<'a, 'p, 'w, 'd, ID, A, S, E, X>
where
    A: app::Lifecycle<'w, 'd, ID> + app::Scheduling<'d, ID>,
    S: attempt::Control<'d, E::Transport, ID>,
    E: env::Spec<Wire = A::Wire>,
    E::Transport: dope_net::Transport,
    X: Mode<'d, ID> + liveness::Schedule<'d, ID, <E::Transport as dope_net::Transport>::Prepared>,
{
    pub(in crate::client) fn new(
        machine: pin::Pin<&'a mut engine::Machine<'p, 'w, 'd, ID, A, S, E, X>>,
    ) -> Self {
        Self { machine }
    }

    pub(in crate::client::conn::engine) fn poll(
        self,
        turn: schedule::Turn<'_, 'd>,
        driver: &mut retained::Context<'_, '_, 'd>,
    ) -> Source
    where
        engine::Machine<'p, 'w, 'd, ID, A, S, E, X>:
            opens::Phase<'d, ID, A, S, E, A::Deferred, <A::Wire as wire::Spec>::OpenFailure>,
    {
        let now = driver.driver_ref().clock().now();
        let mut this = self.machine;
        if !this.as_ref().project_ref().shutdown.is_open() {
            return Source::Idle;
        }
        let woke = {
            let target = this.as_ref().backoff();
            let wake = wake::Waker::from(target);
            this.as_mut()
                .project()
                .drive
                .as_mut()
                .poll_backoff(now, wake)
                .is_ready()
        };
        if !this.as_ref().project_ref().controller.is_pending() && !woke {
            return Source::Idle;
        }
        let cap = this.as_ref().project_ref().links.capacity();
        for _ in 0..cap.entries().get() {
            use opens::Step;
            let step = turn.reborrow().maint().run(|| {
                match opens::Phase::poll(this.as_mut(), now, driver) {
                    Step::Idle => None,
                    step => Some(step),
                }
            });
            let action = match step {
                quota::Admission::Item(action) => action,
                quota::Admission::Empty => break,
                quota::Admission::Exhausted => return Source::Deferred,
            };
            match action {
                Step::Continue => {}
                Step::Stop => return Source::Idle,
                Step::Retry => {
                    return Dial { machine: this }.defer_retry(now);
                }
                Step::Backoff(at) => {
                    let target = this.as_ref().backoff();
                    let wake = wake::Waker::from(target);
                    this.as_mut().project().drive.as_mut().arm_backoff(at, wake);
                    break;
                }
                Step::Idle => break,
            }
        }
        Source::Idle
    }

    pub(in crate::client) fn retry_ready(mut self, driver: &mut driver::Context<'_, 'd>) -> Retry {
        if !self.machine.as_ref().project_ref().drive.has_retry() {
            return Retry::Ready;
        }
        let now = driver.driver_ref().clock().now();
        let target = self.machine.as_ref().backoff();
        let wake = wake::Waker::from(target);
        if self
            .machine
            .as_mut()
            .project()
            .drive
            .as_mut()
            .poll_retry(now, wake)
            .is_ready()
        {
            Retry::Ready
        } else {
            Retry::Pending
        }
    }

    pub(in crate::client) fn defer_retry(mut self, now: clock::Moment<'d>) -> Source {
        let target = self.machine.as_ref().backoff();
        let wake = wake::Waker::from(target);
        self.machine
            .as_mut()
            .project()
            .drive
            .as_mut()
            .defer_retry(now, wake);
        Source::Deferred
    }

    pub(in crate::client) fn finish_retry(self) {
        self.machine.project().drive.as_mut().reset_retry();
    }
}