dope-manifold 0.36.0

Owned application and service composition for dope
use app::failure::{self, Controlled, Observed};
use dope_core::driver::{self, route::Identity};
use dope_net::link::event;

use crate::{
    client::{
        app,
        attempt::{self, queue},
    },
    service::{self, discover, sync},
};

pub(super) trait Fail<'d, ID: Identity, A, S, T>: failure::Mode + Sized
where
    A: app::Application<'d, ID, Failure = Self>,
    S: attempt::Control<'d, T, ID>,
    T: dope_net::Transport,
{
    fn fail(
        ctrl: &mut S,
        app: &mut A,
        owner: attempt::Id<'d, ID>,
        cause: event::ConnectError,
        driver: &mut driver::Context<'_, 'd>,
    );
}

impl<'q, 'h, 'd, ID: Identity + 'd, A, T, R, I, const N: usize, F>
    Fail<'d, ID, A, service::Pool<'q, 'h, 'd, ID, T, R, I, N, F>, T> for Controlled
where
    A: app::Application<'d, ID, Failure = Self>,
    T: dope_net::Transport,
    R: sync::Policy,
    I: Eq,
    F: discover::Feedback,
{
    fn fail(
        ctrl: &mut service::Pool<'q, 'h, 'd, ID, T, R, I, N, F>,
        _: &mut A,
        owner: attempt::Id<'d, ID>,
        cause: event::ConnectError,
        driver: &mut driver::Context<'_, 'd>,
    ) {
        let now = driver.driver_ref().clock().now();
        ctrl.fail(owner, cause, now);
    }
}

impl<'q, 'h, 'd, ID: Identity + 'd, A, T, R, I, const N: usize, F>
    Fail<'d, ID, A, service::Pool<'q, 'h, 'd, ID, T, R, I, N, F>, T> for Observed
where
    A: app::Application<'d, ID, Failure = Self> + app::Failed<'d, ID>,
    T: dope_net::Transport,
    R: sync::Policy,
    I: Eq,
    F: discover::Feedback,
{
    fn fail(
        ctrl: &mut service::Pool<'q, 'h, 'd, ID, T, R, I, N, F>,
        app: &mut A,
        owner: attempt::Id<'d, ID>,
        cause: event::ConnectError,
        driver: &mut driver::Context<'_, 'd>,
    ) {
        let now = driver.driver_ref().clock().now();
        ctrl.fail(owner, cause, now);
        app::Failed::failed(
            app,
            attempt::Completion::reported(owner, ctrl),
            attempt::ConnectFault::Transport(cause),
            driver,
        );
    }
}

impl<'source, 'd, ID: Identity + 'd, A, T> Fail<'d, ID, A, queue::Control<'source, 'd, T, ID>, T>
    for Observed
where
    A: app::Application<'d, ID, Failure = Self> + app::Failed<'d, ID>,
    T: dope_net::Transport,
{
    fn fail(
        ctrl: &mut queue::Control<'source, 'd, T, ID>,
        app: &mut A,
        owner: attempt::Id<'d, ID>,
        cause: event::ConnectError,
        driver: &mut driver::Context<'_, 'd>,
    ) {
        let (owner, cause) = match ctrl.failed(owner) {
            Ok(attempt::Transition::Applied) => (owner, attempt::ConnectFault::Transport(cause)),
            Ok(attempt::Transition::Stale) => return,
            Err(error) if error.is_stale() => return,
            Err(error) => {
                let (owner, error) = error.into_event();
                let cause = attempt::ConnectFault::Cleanup { cause, error };
                (owner, cause)
            }
        };
        app::Failed::failed(
            app,
            attempt::Completion::reported(owner, ctrl),
            cause,
            driver,
        );
    }
}