hibana 0.9.6

Choreography-derived runtime enforcement kernel for no_std Rust multiparty protocols
Documentation
use super::{
    EffList,
    scope_ranges::{
        parallel_arm_ranges_from_enter, parallel_enter_at, route_arm_ranges_from_first_enter,
        route_enter_at,
    },
};

#[cfg(kani)]
mod kani;

#[derive(Clone, Copy, PartialEq, Eq)]
pub(crate) enum FirstVisibleController {
    Absent,
    Unique(u8),
    Ambiguous,
}

impl FirstVisibleController {
    pub(crate) const fn merge(self, other: Self) -> Self {
        match (self, other) {
            (Self::Absent, candidate) | (candidate, Self::Absent) => candidate,
            (Self::Unique(left), Self::Unique(right)) if left == right => Self::Unique(left),
            (Self::Unique(_), Self::Unique(_)) | (Self::Ambiguous, _) | (_, Self::Ambiguous) => {
                Self::Ambiguous
            }
        }
    }

    pub(crate) const fn unique(self) -> Option<u8> {
        match self {
            Self::Unique(role) => Some(role),
            Self::Absent | Self::Ambiguous => None,
        }
    }
}

pub(crate) const fn first_visible_controller<const E: usize>(
    eff_list: &EffList<E>,
    start: usize,
    end: usize,
) -> FirstVisibleController {
    let markers = eff_list.scope_markers();
    if start >= end || start >= eff_list.len() {
        return FirstVisibleController::Absent;
    }
    if let Some(route_enter) = route_enter_at(markers, start, end, 0) {
        let [(arm0_start, arm0_end), (arm1_start, arm1_end)] =
            route_arm_ranges_from_first_enter(markers, route_enter);
        return first_visible_controller(eff_list, arm0_start, arm0_end)
            .merge(first_visible_controller(eff_list, arm1_start, arm1_end));
    }
    if let Some(par_enter) = parallel_enter_at(markers, start, end, 0) {
        let Some((arm0_start, arm0_end, arm1_start, arm1_end)) =
            parallel_arm_ranges_from_enter(markers, par_enter)
        else {
            crate::invariant();
        };
        return first_visible_controller(eff_list, arm0_start, arm0_end)
            .merge(first_visible_controller(eff_list, arm1_start, arm1_end));
    }

    FirstVisibleController::Unique(eff_list.atom_at(start).from)
}