hibana 0.9.2

Session-typed choreographic programming for no_std Rust protocols, inspired by affine MPST
Documentation
use super::{
    Arm, CursorEndpoint, RecvError, RecvResult, ScopeId, TapFrameMeta, Transport, emit, events,
    state_index_to_usize,
};

#[repr(u8)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(in crate::endpoint::kernel) enum IngressEvidenceState {
    Absent = 0,
    Ready = 1,
}

impl IngressEvidenceState {
    #[inline]
    pub(in crate::endpoint::kernel) const fn is_ready(self) -> bool {
        matches!(self, Self::Ready)
    }
}

impl<'r, const ROLE: u8, T> CursorEndpoint<'r, ROLE, T>
where
    T: Transport + 'r,
{
    pub(crate) fn is_reentry_route(&self, scope: ScopeId) -> bool {
        self.cursor.route_scope_reentry(scope)
    }

    pub(crate) fn selected_arm_for_scope(&self, scope: ScopeId) -> Option<u8> {
        if scope.is_none() {
            return None;
        }
        let scope_slot = self.scope_slot_for_route(scope)?;
        self.decision_state.selected_arm_for_scope_slot(scope_slot)
    }

    pub(crate) fn route_scope_offer_entry_index(&self, scope_id: ScopeId) -> Option<usize> {
        let offer_entry = self.cursor.route_scope_offer_entry(scope_id)?;
        Some(if offer_entry.is_absent() {
            self.cursor.index()
        } else {
            state_index_to_usize(offer_entry)
        })
    }

    pub(crate) fn preview_passive_materialization_index_for_selected_arm(
        &self,
        scope_id: ScopeId,
        arm: u8,
    ) -> Option<usize> {
        self.cursor
            .passive_materialization_index_for_selected_arm(scope_id, arm, |scope| {
                self.preview_selected_arm_for_scope(scope)
            })
    }

    pub(crate) fn preview_selected_arm_for_scope(&self, scope_id: ScopeId) -> Option<u8> {
        if let Some(arm) = self.selected_arm_for_scope(scope_id) {
            return Some(arm);
        }
        self.preview_route_arm_selection_non_consuming(scope_id)
            .map(Arm::as_u8)
            .or_else(|| self.poll_arm_from_ready_mask(scope_id).map(Arm::as_u8))
    }

    #[inline]
    pub(crate) fn current_offer_scope_id(&self) -> ScopeId {
        let mut selected_arm_for_scope = |scope| self.selected_arm_for_scope(scope);
        let mut preview_selected_arm_for_scope = |scope| {
            self.preview_route_arm_selection_non_consuming(scope)
                .map(Arm::as_u8)
                .or_else(|| self.poll_arm_from_ready_mask(scope).map(Arm::as_u8))
        };
        self.cursor.current_offer_scope_id(
            &mut selected_arm_for_scope,
            &mut preview_selected_arm_for_scope,
        )
    }

    pub(crate) fn rebase_passive_descendant_scope(
        &self,
        stop_scope: ScopeId,
        initial_scope: ScopeId,
    ) -> ScopeId {
        self.cursor
            .rebase_passive_descendant_scope(stop_scope, initial_scope, |scope| {
                self.selected_arm_for_scope(scope)
                    .or_else(|| self.preview_selected_arm_for_scope(scope))
            })
    }

    pub(crate) fn current_route_arm_authorized(&self) -> RecvResult<bool> {
        self.cursor
            .current_route_arm_authorization(
                |scope| self.selected_arm_for_scope(scope),
                |scope| self.preview_selected_arm_for_scope(scope),
            )
            .map(|authorization| authorization.authorizes_current_arm())
            .map_err(|_| RecvError::PhaseInvariant)
    }

    pub(crate) fn emit_endpoint_event(&self, id: u16, meta: TapFrameMeta, lane: u8) {
        let port = self.port_for_lane(lane as usize);
        let packed =
            ((ROLE as u32) << 24) | ((meta.lane as u32) << 16) | ((meta.label as u32) << 8);
        let event = events::raw_event(port.now32(), id)
            .with_arg0(meta.sid)
            .with_arg1(packed);
        emit(port.tap(), event);
    }
}