hibana 0.9.4

Session-typed choreographic programming for no_std Rust protocols, inspired by affine MPST
Documentation
use super::evidence::{
    MatchAccumulator, MatchOutcome, ObservedInboundKey, RecvCandidate, RecvDescriptor,
};
use crate::{
    endpoint::kernel::{core::CursorEndpoint, lane_port},
    endpoint::{RecvError, RecvResult},
    global::typestate::{EventCommitMeta, StateIndex},
    transport::Transport,
};

impl<'r, const ROLE: u8, T> CursorEndpoint<'r, ROLE, T>
where
    T: Transport + 'r,
{
    pub(in crate::endpoint::kernel::recv) fn live_recv_label_on_lane(
        &self,
        lane_idx: usize,
        target_label: u8,
    ) -> bool {
        let mut idx = 0usize;
        while idx < self.cursor.local_steps_len() {
            if let Some(meta) = self.cursor.try_recv_meta_at(idx)
                && meta.label == target_label
                && meta.lane as usize == lane_idx
                && !meta.origin.is_session()
                && {
                    let preview_conflict = self.cursor.event_conflict_for_index(idx);
                    let mut selected_arm =
                        |scope| self.selected_arm_for_recv_event(preview_conflict, scope);
                    self.cursor
                        .event_enabled(idx, EventCommitMeta::from(meta), &mut selected_arm)
                        .is_ok()
                }
            {
                return true;
            }
            idx += 1;
        }
        false
    }

    fn recv_candidate_for_observed_evidence(
        &self,
        idx: usize,
        target_label: u8,
        observed: ObservedInboundKey,
    ) -> RecvResult<Option<RecvCandidate>> {
        let Some(meta) = self.cursor.try_recv_meta_at(idx) else {
            return Ok(None);
        };
        if meta.label != target_label {
            return Ok(None);
        }
        if meta.origin.is_session() {
            return Err(RecvError::PhaseInvariant);
        }
        let lane_idx = meta.lane as usize;
        if lane_idx >= self.cursor.logical_lane_count() {
            return Err(RecvError::PhaseInvariant);
        }
        let lane_wire = self.port_for_lane(lane_idx).lane().as_wire();
        if !observed.matches_recv_meta(self.sid.raw(), lane_wire, ROLE, meta) {
            return Ok(None);
        }
        let preview_conflict = self.cursor.event_conflict_for_index(idx);
        let mut selected_arm = |scope| self.selected_arm_for_recv_event(preview_conflict, scope);
        let enabled =
            self.cursor
                .event_enabled(idx, EventCommitMeta::from(meta), &mut selected_arm);
        if enabled.is_err() {
            return Ok(None);
        }

        Ok(Some(RecvCandidate {
            desc: RecvDescriptor {
                meta,
                cursor_index: StateIndex::from_usize(idx),
                lane_idx,
                lane_wire,
            },
        }))
    }

    fn recv_candidate_for_deterministic_lane(
        &self,
        idx: usize,
        target_label: u8,
        lane_wire: u8,
    ) -> RecvResult<Option<RecvCandidate>> {
        let Some(meta) = self.cursor.try_recv_meta_at(idx) else {
            return Ok(None);
        };
        if meta.label != target_label {
            return Ok(None);
        }
        if meta.origin.is_session() {
            return Err(RecvError::PhaseInvariant);
        }
        let lane_idx = meta.lane as usize;
        if lane_idx >= self.cursor.logical_lane_count() {
            return Err(RecvError::PhaseInvariant);
        }
        let candidate_lane_wire = self.port_for_lane(lane_idx).lane().as_wire();
        if candidate_lane_wire != lane_wire {
            return Ok(None);
        }
        let preview_conflict = self.cursor.event_conflict_for_index(idx);
        let mut selected_arm = |scope| self.selected_arm_for_recv_event(preview_conflict, scope);
        let enabled =
            self.cursor
                .event_enabled(idx, EventCommitMeta::from(meta), &mut selected_arm);
        if enabled.is_err() {
            return Ok(None);
        }

        Ok(Some(RecvCandidate {
            desc: RecvDescriptor {
                meta,
                cursor_index: StateIndex::from_usize(idx),
                lane_idx,
                lane_wire: candidate_lane_wire,
            },
        }))
    }

    pub(in crate::endpoint::kernel::recv) fn unique_recv_candidate(
        &self,
        target_label: u8,
        observed: ObservedInboundKey,
    ) -> RecvResult<Result<RecvCandidate, MatchOutcome>> {
        let mut accumulator = MatchAccumulator::None;
        let mut idx = 0usize;
        while idx < self.cursor.local_steps_len() {
            if let Some(candidate) =
                self.recv_candidate_for_observed_evidence(idx, target_label, observed)?
            {
                accumulator = accumulator.add(candidate);
                if matches!(accumulator, MatchAccumulator::Ambiguous) {
                    break;
                }
            }
            idx += 1;
        }
        Ok(accumulator.finish())
    }

    pub(in crate::endpoint::kernel::recv) fn unique_deterministic_recv_candidate(
        &self,
        target_label: u8,
        lane_wire: u8,
    ) -> RecvResult<Result<RecvCandidate, MatchOutcome>> {
        let mut accumulator = MatchAccumulator::None;
        let mut idx = 0usize;
        while idx < self.cursor.local_steps_len() {
            if let Some(candidate) =
                self.recv_candidate_for_deterministic_lane(idx, target_label, lane_wire)?
            {
                accumulator = accumulator.add(candidate);
                if matches!(accumulator, MatchAccumulator::Ambiguous) {
                    break;
                }
            }
            idx += 1;
        }
        Ok(accumulator.finish())
    }

    pub(in crate::endpoint::kernel::recv) fn framed_recv_mismatch_for_unmatched_candidate(
        &self,
        target_label: u8,
        frame: &lane_port::PreambleFrame<'_>,
    ) -> lane_port::FrameMismatch {
        let observed = frame.observed_transport_frame(self.sid.raw(), frame.lane_wire(), ROLE);
        match self.unique_deterministic_recv_candidate(target_label, frame.lane_wire()) {
            Ok(Ok(candidate)) => lane_port::FrameMismatch::source_label_mismatch(
                observed,
                candidate.desc.meta.peer,
                candidate.desc.meta.frame_label,
            ),
            Ok(Err(_)) | Err(_) => lane_port::FrameMismatch::label_mismatch(observed),
        }
    }
}