hibana 0.9.6

Choreography-derived runtime enforcement kernel for no_std Rust multiparty protocols
Documentation
use super::{
    ScopeKind, ScopeMarkerView, closed_route_arm_ranges_from_first_enter,
    parallel_arm_ranges_from_enter, route_arm_ranges_from_first_enter,
};

const fn route_arm_at(
    markers: ScopeMarkerView<'_>,
    route_enter_idx: usize,
    eff_idx: usize,
) -> Option<u8> {
    let [(left_start, left_end), (right_start, right_end)] =
        route_arm_ranges_from_first_enter(markers, route_enter_idx);
    if left_start <= eff_idx && eff_idx < left_end {
        Some(0)
    } else if right_start <= eff_idx && eff_idx < right_end {
        Some(1)
    } else {
        None
    }
}

pub(super) const fn events_share_route_path(
    markers: ScopeMarkerView<'_>,
    left_eff_idx: usize,
    right_eff_idx: usize,
) -> bool {
    let mut marker_idx = 0usize;
    while marker_idx < markers.len() {
        let marker = markers.at(marker_idx);
        if matches!(marker.scope_id.kind(), Some(ScopeKind::Route))
            && markers.is_first_enter(marker_idx)
            && closed_route_arm_ranges_from_first_enter(markers, marker_idx).is_some()
        {
            match (
                route_arm_at(markers, marker_idx, left_eff_idx),
                route_arm_at(markers, marker_idx, right_eff_idx),
            ) {
                (None, None) | (Some(0), Some(0)) | (Some(1), Some(1)) => {}
                _ => return false,
            }
        }
        marker_idx += 1;
    }
    true
}

const fn parallel_arm_at(
    markers: ScopeMarkerView<'_>,
    parallel_enter_idx: usize,
    eff_idx: usize,
) -> Option<u8> {
    let Some((left_start, left_end, right_start, right_end)) =
        parallel_arm_ranges_from_enter(markers, parallel_enter_idx)
    else {
        panic!("parallel scope arm range missing");
    };
    if left_start <= eff_idx && eff_idx < left_end {
        Some(0)
    } else if right_start <= eff_idx && eff_idx < right_end {
        Some(1)
    } else {
        None
    }
}

pub(super) const fn events_are_route_exclusive(
    markers: ScopeMarkerView<'_>,
    left_eff_idx: usize,
    right_eff_idx: usize,
) -> bool {
    let mut marker_idx = 0usize;
    while marker_idx < markers.len() {
        let marker = markers.at(marker_idx);
        if matches!(marker.scope_id.kind(), Some(ScopeKind::Route))
            && markers.is_first_enter(marker_idx)
        {
            let left_arm = route_arm_at(markers, marker_idx, left_eff_idx);
            let right_arm = route_arm_at(markers, marker_idx, right_eff_idx);
            if matches!(
                (left_arm, right_arm),
                (Some(0), Some(1)) | (Some(1), Some(0))
            ) {
                return true;
            }
        }
        marker_idx += 1;
    }
    false
}

pub(super) const fn events_are_parallel(
    markers: ScopeMarkerView<'_>,
    left_eff_idx: usize,
    right_eff_idx: usize,
) -> bool {
    let mut marker_idx = 0usize;
    while marker_idx < markers.len() {
        let marker = markers.at(marker_idx);
        if marker.event.is_primary_enter()
            && matches!(marker.scope_id.kind(), Some(ScopeKind::Parallel))
        {
            let left_arm = parallel_arm_at(markers, marker_idx, left_eff_idx);
            let right_arm = parallel_arm_at(markers, marker_idx, right_eff_idx);
            if matches!(
                (left_arm, right_arm),
                (Some(0), Some(1)) | (Some(1), Some(0))
            ) {
                return true;
            }
        }
        marker_idx += 1;
    }
    false
}

pub(super) const fn events_are_locally_ordered(
    markers: ScopeMarkerView<'_>,
    earlier_eff_idx: usize,
    later_eff_idx: usize,
) -> bool {
    earlier_eff_idx < later_eff_idx
        && !events_are_parallel(markers, earlier_eff_idx, later_eff_idx)
        && !events_are_route_exclusive(markers, earlier_eff_idx, later_eff_idx)
}