hibana 0.8.0

Const-projected Affine Multiparty Session Types for choreography-first Rust protocols
Documentation
use super::super::super::{ObservedEntrySet, OfferSelectPriority};
use super::entry::{CurrentOfferEntry, OfferAlignmentCandidateInput};
use super::set::OfferEntrySet;

#[derive(Clone, Copy)]
pub(in crate::endpoint::kernel::offer::select_alignment) struct CurrentOfferObservation {
    present: bool,
    ready: bool,
    progress_evidence: bool,
    observed_progress_evidence: bool,
    controller_progress_sibling_exists: bool,
}

impl CurrentOfferObservation {
    #[inline]
    const fn new(
        present: bool,
        ready: bool,
        progress_evidence: bool,
        observed_progress_evidence: bool,
        controller_progress_sibling_exists: bool,
    ) -> Self {
        Self {
            present,
            ready,
            progress_evidence,
            observed_progress_evidence,
            controller_progress_sibling_exists,
        }
    }

    #[inline]
    pub(in crate::endpoint::kernel::offer::select_alignment) const fn present(self) -> bool {
        self.present
    }

    #[inline]
    pub(in crate::endpoint::kernel::offer::select_alignment) const fn ready(self) -> bool {
        self.ready
    }

    #[inline]
    pub(in crate::endpoint::kernel::offer::select_alignment) const fn progress_evidence(
        self,
    ) -> bool {
        self.progress_evidence
    }

    #[inline]
    pub(in crate::endpoint::kernel::offer::select_alignment) const fn accumulated_progress_evidence(
        self,
        state_evidence: bool,
    ) -> bool {
        self.observed_progress_evidence || state_evidence
    }

    #[inline]
    pub(in crate::endpoint::kernel::offer::select_alignment) const fn controller_progress_sibling_exists(
        self,
    ) -> bool {
        self.controller_progress_sibling_exists
    }
}

#[derive(Clone, Copy)]
pub(in crate::endpoint::kernel::offer::select_alignment) struct OfferAlignmentCandidatePool {
    observed_entries: OfferEntrySet,
    ready_entries: OfferEntrySet,
    ready_arm_entries: OfferEntrySet,
    controller_entries: OfferEntrySet,
    dynamic_controller_entries: OfferEntrySet,
    progress_entries: OfferEntrySet,
    current_entry_slot: OfferEntrySet,
}

#[derive(Clone, Copy)]
pub(in crate::endpoint::kernel::offer::select_alignment) enum OfferAlignmentOutcome {
    NoCandidate,
    AmbiguousCandidates,
    UniqueDynamicController(usize),
    UniqueController(usize),
    UniqueCandidate(usize),
}

#[derive(Clone, Copy)]
pub(in crate::endpoint::kernel::offer::select_alignment) struct OfferAlignmentSelection {
    hint_filter: Option<usize>,
    outcome: OfferAlignmentOutcome,
}

impl OfferAlignmentSelection {
    #[inline]
    pub(in crate::endpoint::kernel::offer::select_alignment) const fn has_candidate(self) -> bool {
        !matches!(self.outcome, OfferAlignmentOutcome::NoCandidate)
    }

    #[inline]
    pub(in crate::endpoint::kernel::offer::select_alignment) const fn allows_current(
        self,
        current_idx: usize,
    ) -> bool {
        match self.hint_filter {
            Some(filtered_idx) => current_idx == filtered_idx,
            None => true,
        }
    }

    #[inline]
    pub(in crate::endpoint::kernel::offer::select_alignment) const fn select(
        self,
        current_is_candidate: bool,
        current_idx: usize,
    ) -> Option<(OfferSelectPriority, usize)> {
        if current_is_candidate {
            return Some((OfferSelectPriority::CurrentOfferEntry, current_idx));
        }
        match self.outcome {
            OfferAlignmentOutcome::UniqueDynamicController(idx) => {
                Some((OfferSelectPriority::DynamicControllerUnique, idx))
            }
            OfferAlignmentOutcome::UniqueController(idx) => {
                Some((OfferSelectPriority::ControllerUnique, idx))
            }
            OfferAlignmentOutcome::UniqueCandidate(idx) => {
                Some((OfferSelectPriority::CandidateUnique, idx))
            }
            OfferAlignmentOutcome::NoCandidate | OfferAlignmentOutcome::AmbiguousCandidates => None,
        }
    }
}

struct ClassifiedOfferCandidateSets {
    candidates: OfferEntrySet,
    controllers: OfferEntrySet,
    dynamic_controllers: OfferEntrySet,
}

impl ClassifiedOfferCandidateSets {
    #[inline]
    const fn new(
        candidates: OfferEntrySet,
        controllers: OfferEntrySet,
        dynamic_controllers: OfferEntrySet,
    ) -> Self {
        Self {
            candidates,
            controllers,
            dynamic_controllers,
        }
    }

    fn outcome(self, observed_entries: ObservedEntrySet) -> OfferAlignmentOutcome {
        if self.dynamic_controllers.has_one() {
            return self
                .dynamic_controllers
                .first_entry_idx(observed_entries)
                .map(OfferAlignmentOutcome::UniqueDynamicController)
                .unwrap_or(OfferAlignmentOutcome::AmbiguousCandidates);
        }
        if self.controllers.has_one() {
            return self
                .controllers
                .first_entry_idx(observed_entries)
                .map(OfferAlignmentOutcome::UniqueController)
                .unwrap_or(OfferAlignmentOutcome::AmbiguousCandidates);
        }
        if self.candidates.is_empty() {
            return OfferAlignmentOutcome::NoCandidate;
        }
        if self.candidates.has_one() {
            return self
                .candidates
                .first_entry_idx(observed_entries)
                .map(OfferAlignmentOutcome::UniqueCandidate)
                .unwrap_or(OfferAlignmentOutcome::AmbiguousCandidates);
        }
        OfferAlignmentOutcome::AmbiguousCandidates
    }
}

impl OfferAlignmentCandidatePool {
    #[inline]
    pub(in crate::endpoint::kernel::offer::select_alignment) fn from_observed(
        observed_entries: ObservedEntrySet,
        selectable: OfferEntrySet,
        input: OfferAlignmentCandidateInput,
    ) -> Self {
        let observed =
            OfferEntrySet::from_bits(observed_entries.occupancy_mask()).intersect(selectable);
        let current_entry_slot =
            OfferEntrySet::from_bits(observed_entries.entry_bit(input.current_idx));
        let raw_progress = OfferEntrySet::from_bits(observed_entries.progress_mask);
        let progress_entries = if input.current_entry.is_route_entry() {
            raw_progress.intersect(observed)
        } else {
            raw_progress.intersect(observed).without(current_entry_slot)
        };
        Self {
            observed_entries: observed,
            ready_entries: OfferEntrySet::from_bits(observed_entries.ready_mask)
                .intersect(observed),
            ready_arm_entries: OfferEntrySet::from_bits(observed_entries.ready_arm_mask)
                .intersect(observed),
            controller_entries: OfferEntrySet::from_bits(observed_entries.controller_mask)
                .intersect(observed),
            dynamic_controller_entries: OfferEntrySet::from_bits(
                observed_entries.dynamic_controller_mask,
            )
            .intersect(observed),
            progress_entries,
            current_entry_slot,
        }
    }

    #[inline]
    const fn current_matches_route(self, entry: CurrentOfferEntry) -> bool {
        !self.current_entry_slot.is_empty() && entry.is_route_entry()
    }

    #[inline]
    pub(in crate::endpoint::kernel::offer::select_alignment) const fn current_observation(
        self,
        observed_entries: ObservedEntrySet,
    ) -> CurrentOfferObservation {
        let raw_progress_entries = OfferEntrySet::from_bits(observed_entries.progress_mask);
        CurrentOfferObservation::new(
            !self.current_entry_slot.is_empty(),
            self.current_entry_slot.intersects(self.ready_entries),
            self.current_entry_slot.intersects(self.progress_entries),
            self.current_entry_slot.intersects(raw_progress_entries),
            !self
                .progress_entries
                .intersect(self.controller_entries)
                .without(self.current_entry_slot)
                .is_empty(),
        )
    }

    #[inline]
    pub(in crate::endpoint::kernel::offer::select_alignment) const fn suppresses_current_controller_without_evidence(
        self,
        observed_entries: ObservedEntrySet,
        input: OfferAlignmentCandidateInput,
    ) -> bool {
        input.current_authority.is_controller()
            && self.current_matches_route(input.current_entry)
            && self
                .current_entry_slot
                .intersect(OfferEntrySet::from_bits(observed_entries.ready_arm_mask))
                .is_empty()
            && self
                .current_entry_slot
                .intersect(OfferEntrySet::from_bits(observed_entries.progress_mask))
                .is_empty()
            && input.progress_sibling_exists
    }

    #[inline]
    pub(in crate::endpoint::kernel::offer::select_alignment) const fn static_controller_frontier(
        self,
        suppress_current: bool,
    ) -> OfferEntrySet {
        let mut ready = self.observed_entries.without(self.controller_entries);
        ready = ready.union(self.current_entry_slot.intersect(self.controller_entries));
        ready = ready.union(self.progress_entries.intersect(self.controller_entries));
        if suppress_current {
            ready = ready.without(self.current_entry_slot);
        }
        ready
    }

    #[inline]
    pub(in crate::endpoint::kernel::offer::select_alignment) const fn arbitration_frontier(
        self,
        input: OfferAlignmentCandidateInput,
        static_controller_frontier: OfferEntrySet,
    ) -> OfferEntrySet {
        let mut candidates = self.progress_entries;
        if self.current_matches_route(input.current_entry) {
            candidates = candidates.union(self.current_entry_slot);
        }
        if input.current_entry.is_unrunnable_route() {
            candidates = candidates.union(self.observed_entries.without(self.current_entry_slot));
        }
        candidates.intersect(static_controller_frontier)
    }

    #[inline]
    pub(in crate::endpoint::kernel::offer::select_alignment) const fn hinted_frontier(
        self,
        candidates: OfferEntrySet,
    ) -> OfferEntrySet {
        candidates
            .intersect(self.ready_arm_entries)
            .unique_or_empty()
    }

    pub(in crate::endpoint::kernel::offer::select_alignment) fn selection(
        self,
        observed_entries: ObservedEntrySet,
        input: OfferAlignmentCandidateInput,
        static_controller_frontier: OfferEntrySet,
    ) -> OfferAlignmentSelection {
        let candidates = self.arbitration_frontier(input, static_controller_frontier);
        let hinted = self.hinted_frontier(candidates);
        let hint_filter = hinted.first_entry_idx(observed_entries);
        let candidates = if !hinted.is_empty() {
            hinted
        } else {
            candidates
        };
        let controllers = candidates.intersect(self.controller_entries);
        let dynamic_controllers = controllers.intersect(self.dynamic_controller_entries);
        let outcome =
            ClassifiedOfferCandidateSets::new(candidates, controllers, dynamic_controllers)
                .outcome(observed_entries);

        OfferAlignmentSelection {
            hint_filter,
            outcome,
        }
    }
}