dope 0.12.0

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

use dope_core::backend::Sqe;
use dope_core::driver::submission::Submission;
use dope_core::driver::token::SlotIndex;
use dope_core::driver::token::kind::{CONNECT, SOCKET};
use dope_net::Transport;
use dope_net::link::slot::{PEND_CLOSE, PendingQueue};

use super::{ConnPool, Core};
use crate::DriverContext;
use crate::manifold::connector::app::ConnApp;
use crate::manifold::connector::source::Dialer;
use crate::manifold::env::Env;

pub(super) trait ClosePhase<'d, const ID: u8, A, S, E>
where
    A: ConnApp<'d>,
    S: Dialer<E::Transport>,
    E: Env<Wire = A::Wire>,
    E::Transport: Transport,
{
    fn flush_cancellations(self: Pin<&mut Self>);

    fn close_slot(self: Pin<&mut Self>, idx: SlotIndex, driver: &mut DriverContext<'_, 'd>);

    fn drain_close(
        pool: &mut ConnPool<'d, ID, E::Transport, A::Wire, A::Conn, A::Send>,
        dirty: &PendingQueue,
        app: &A,
        idx: SlotIndex,
        driver: &mut DriverContext<'_, 'd>,
    );

    fn maybe_close(self: Pin<&mut Self>, idx: SlotIndex, driver: &mut DriverContext<'_, 'd>);
}

impl<'d, const ID: u8, A, S, E> ClosePhase<'d, ID, A, S, E> for Core<'d, ID, A, S, E>
where
    A: ConnApp<'d>,
    S: Dialer<E::Transport>,
    E: Env<Wire = A::Wire>,
    E::Transport: Transport,
{
    fn flush_cancellations(mut self: Pin<&mut Self>) {
        loop {
            let cancel = self.as_ref().project_ref().app.take_cancel();
            let Some((key, idx)) = cancel else {
                break;
            };
            let this = self.as_mut().project();
            let Some(slot) = this.pool.get(idx) else {
                continue;
            };
            if slot.state.dial == key {
                this.dirty.mark(idx, &slot.state.pending, PEND_CLOSE);
            }
        }
    }

    fn close_slot(self: Pin<&mut Self>, idx: SlotIndex, driver: &mut DriverContext<'_, 'd>) {
        let now = driver.turn_now();
        let this = self.project();
        let slot_meta = this.pool.get_mut(idx).and_then(|slot| {
            if slot.state.retired {
                return None;
            }
            slot.state.retired = true;
            let established = slot.state.establish.is_done();
            let key = slot.state.dial;
            let permanent = slot.state.close_permanent;
            if established {
                this.app.close(slot, driver);
            }
            Some((key, permanent))
        });
        if let Some((key, permanent)) = slot_meta {
            if permanent {
                this.upstreams.kill(key);
            } else {
                this.upstreams.disconnect(key, now);
            }
        }
        Self::drain_close(this.pool, this.dirty, this.app, idx, driver);
    }

    fn drain_close(
        pool: &mut ConnPool<'d, ID, E::Transport, A::Wire, A::Conn, A::Send>,
        dirty: &PendingQueue,
        app: &A,
        idx: SlotIndex,
        driver: &mut DriverContext<'_, 'd>,
    ) {
        let (send_inflight, establishing, connecting, token) = match pool.get(idx) {
            Some(slot) => (
                slot.core.is_send_inflight(),
                !slot.state.establish.is_done(),
                slot.state.establish.is_connecting(),
                slot.token(),
            ),
            None => return,
        };
        if establishing {
            let op_kind = if connecting { CONNECT } else { SOCKET };
            let cancel = if connecting {
                Sqe::cancel(token, op_kind)
            } else {
                let Some(fd) = pool.fd_of(idx) else {
                    return;
                };
                Sqe::cancel_create(fd.slot())
            };
            let cancelled = driver.push(cancel).is_ok();
            if let Some(slot) = pool.get_mut(idx) {
                slot.core.begin_close();
                if !cancelled {
                    dirty.mark(idx, &slot.state.pending, PEND_CLOSE);
                }
            }
            return;
        }
        if send_inflight {
            if let Some(slot) = pool.get_mut(idx) {
                slot.core.begin_close();
            }
            return;
        }
        if pool
            .get_mut(idx)
            .is_some_and(|slot| slot.seal_graceful(driver, token))
        {
            return;
        }
        let drained = pool
            .get(idx)
            .map(|slot| app.is_drained(slot, driver))
            .unwrap_or(true);
        if drained {
            pool.try_close(idx, driver);
        } else if let Some(slot) = pool.get_mut(idx) {
            dirty.mark(idx, &slot.state.pending, PEND_CLOSE);
        }
    }

    fn maybe_close(mut self: Pin<&mut Self>, idx: SlotIndex, driver: &mut DriverContext<'_, 'd>) {
        let close = {
            let this = self.as_ref().project_ref();
            let Some(slot) = this.pool.get(idx) else {
                return;
            };
            slot.core.should_close(this.app.defer_close(slot, driver))
        };
        if close {
            self.as_mut().close_slot(idx, driver);
        }
    }
}