hibana 0.9.6

Choreography-derived runtime enforcement kernel for no_std Rust multiparty protocols
Documentation
use super::super::{
    CursorEndpoint, OfferScopeProfile, OfferScopeSelection, ScopeArmMaterializationMeta, Transport,
    profile::{
        OfferArmRecvEvidence, OfferControllerCursorArm, OfferControllerLocalEvidence,
        OfferControllerLocalReadiness, OfferCursorReadiness, OfferEntryPosition,
        OfferMaterializationReadiness, OfferPassiveEvidence, OfferPassiveReadiness,
        OfferPassiveReadySignal, OfferPassiveRecvEvidence,
    },
};
use super::evidence::OfferIngressEvidence;

struct OfferIngressPlannerInput {
    selection: OfferScopeSelection,
    entry: OfferEntryPosition,
    materialization: ScopeArmMaterializationMeta,
    cursor: OfferCursorReadiness,
}

impl<'r, const ROLE: u8, T> CursorEndpoint<'r, ROLE, T>
where
    T: Transport + 'r,
{
    pub(super) fn offer_ingress_evidence(
        &mut self,
        selection: OfferScopeSelection,
        entry: OfferEntryPosition,
        profile: OfferScopeProfile,
    ) -> OfferIngressEvidence {
        let input = OfferIngressPlannerInput {
            selection,
            entry,
            materialization: self.selection_materialization_meta(selection),
            cursor: if self.cursor.is_recv() {
                OfferCursorReadiness::Recv
            } else {
                OfferCursorReadiness::NonRecv
            },
        };

        match profile {
            OfferScopeProfile::ControllerIntrinsic => {
                self.controller_intrinsic_ingress_evidence(input)
            }
            OfferScopeProfile::ControllerDynamic => self.controller_dynamic_ingress_evidence(input),
            OfferScopeProfile::PassiveIntrinsic => self.passive_intrinsic_ingress_evidence(input),
            OfferScopeProfile::PassiveDynamic => self.passive_dynamic_ingress_evidence(input),
        }
    }

    pub(super) fn offer_scope_profile(
        &self,
        scope_id: crate::global::const_dsl::ScopeId,
    ) -> OfferScopeProfile {
        let is_controller = self.cursor.is_route_controller(scope_id);
        let is_dynamic = self.cursor.route_scope_resolver(scope_id).is_some();
        match (is_controller, is_dynamic) {
            (true, true) => OfferScopeProfile::ControllerDynamic,
            (true, false) => OfferScopeProfile::ControllerIntrinsic,
            (false, true) => OfferScopeProfile::PassiveDynamic,
            (false, false) => OfferScopeProfile::PassiveIntrinsic,
        }
    }

    fn controller_intrinsic_ingress_evidence(
        &self,
        input: OfferIngressPlannerInput,
    ) -> OfferIngressEvidence {
        OfferIngressEvidence {
            profile: OfferScopeProfile::ControllerIntrinsic,
            entry: input.entry,
            cursor: input.cursor,
            controller: self.controller_intrinsic_readiness(&input),
            passive: OfferPassiveReadiness::NeedsTransport,
        }
    }

    fn controller_dynamic_ingress_evidence(
        &self,
        input: OfferIngressPlannerInput,
    ) -> OfferIngressEvidence {
        OfferIngressEvidence {
            profile: OfferScopeProfile::ControllerDynamic,
            entry: input.entry,
            cursor: input.cursor,
            controller: self.controller_dynamic_readiness(&input),
            passive: OfferPassiveReadiness::NeedsTransport,
        }
    }

    fn passive_intrinsic_ingress_evidence(
        &self,
        input: OfferIngressPlannerInput,
    ) -> OfferIngressEvidence {
        OfferIngressEvidence {
            profile: OfferScopeProfile::PassiveIntrinsic,
            entry: input.entry,
            cursor: input.cursor,
            controller: OfferControllerLocalReadiness::NeedsTransport,
            passive: self.passive_intrinsic_readiness(&input),
        }
    }

    fn passive_dynamic_ingress_evidence(
        &self,
        input: OfferIngressPlannerInput,
    ) -> OfferIngressEvidence {
        OfferIngressEvidence {
            profile: OfferScopeProfile::PassiveDynamic,
            entry: input.entry,
            cursor: input.cursor,
            controller: OfferControllerLocalReadiness::NeedsTransport,
            passive: self.passive_dynamic_readiness(&input),
        }
    }

    fn controller_intrinsic_readiness(
        &self,
        input: &OfferIngressPlannerInput,
    ) -> OfferControllerLocalReadiness {
        let profile = OfferScopeProfile::ControllerIntrinsic;
        profile.controller_local_readiness(self.controller_local_evidence(input))
    }

    fn controller_dynamic_readiness(
        &self,
        input: &OfferIngressPlannerInput,
    ) -> OfferControllerLocalReadiness {
        let profile = OfferScopeProfile::ControllerDynamic;
        profile.controller_local_readiness(self.controller_local_evidence(input))
    }

    fn controller_local_evidence(
        &self,
        input: &OfferIngressPlannerInput,
    ) -> OfferControllerLocalEvidence {
        OfferControllerLocalEvidence::new(
            input.cursor,
            self.controller_cursor_arm(input),
            self.controller_materialization_readiness(input),
        )
    }

    fn controller_cursor_arm(&self, input: &OfferIngressPlannerInput) -> OfferControllerCursorArm {
        if self
            .controller_arm_at_cursor(input.selection.scope_id)
            .is_some()
        {
            OfferControllerCursorArm::AtArm
        } else {
            OfferControllerCursorArm::OutsideArm
        }
    }

    fn controller_materialization_readiness(
        &self,
        input: &OfferIngressPlannerInput,
    ) -> OfferMaterializationReadiness {
        let Some(arm) = self.selected_arm_for_scope(input.selection.scope_id) else {
            return OfferMaterializationReadiness::Ready;
        };
        if self.arm_requires_materialization_ready_evidence(input.selection.scope_id, arm)
            && !self.scope_has_ready_arm(input.selection.scope_id, arm)
        {
            OfferMaterializationReadiness::Pending
        } else {
            OfferMaterializationReadiness::Ready
        }
    }

    fn passive_intrinsic_readiness(
        &self,
        input: &OfferIngressPlannerInput,
    ) -> OfferPassiveReadiness {
        OfferScopeProfile::PassiveIntrinsic.passive_readiness(OfferPassiveEvidence::new(
            self.passive_ready_signal(input),
            self.passive_recv_evidence(input),
        ))
    }

    fn passive_dynamic_readiness(&self, input: &OfferIngressPlannerInput) -> OfferPassiveReadiness {
        OfferScopeProfile::PassiveDynamic.passive_readiness(OfferPassiveEvidence::new(
            self.passive_ready_signal(input),
            self.passive_recv_evidence(input),
        ))
    }

    fn passive_ready_signal(&self, input: &OfferIngressPlannerInput) -> OfferPassiveReadySignal {
        if self.scope_has_ready_arm_evidence(input.selection.scope_id) {
            OfferPassiveReadySignal::Observed
        } else {
            OfferPassiveReadySignal::Absent
        }
    }

    fn passive_recv_evidence(&self, input: &OfferIngressPlannerInput) -> OfferPassiveRecvEvidence {
        if matches!(
            self.arm_recv_evidence(input, 0),
            OfferArmRecvEvidence::HasRecv
        ) || matches!(
            self.arm_recv_evidence(input, 1),
            OfferArmRecvEvidence::HasRecv
        ) {
            OfferPassiveRecvEvidence::HasRecv
        } else {
            OfferPassiveRecvEvidence::Recvless
        }
    }

    fn arm_recv_evidence(&self, input: &OfferIngressPlannerInput, arm: u8) -> OfferArmRecvEvidence {
        let scope_id = input.selection.scope_id;
        if self.arm_has_recv_with_materialization(scope_id, arm, input.materialization)
            || self
                .compute_passive_arm_recv_meta(scope_id, arm, input.selection.offer_lane)
                .is_recv_step()
        {
            OfferArmRecvEvidence::HasRecv
        } else {
            OfferArmRecvEvidence::Recvless
        }
    }
}