hibana 0.9.6

Choreography-derived runtime enforcement kernel for no_std Rust multiparty protocols
Documentation
use crate::{
    g::ProgramSourceError,
    global::const_dsl::{
        ScopeId, ScopeKind, ScopeMarkerView, passive_route_child_scope,
        route_arm_event_ranges_for_scope, route_parent_arm_for_scope, route_scope_slot_for_scope,
    },
};

pub(super) const fn validate_passive_child_projection_guarantees(
    scope_markers: ScopeMarkerView<'_>,
) -> Option<ProgramSourceError> {
    let mut route_slot = 0usize;
    let mut marker_idx = 0usize;
    while marker_idx < scope_markers.len() {
        let marker = scope_markers.at(marker_idx);
        if scope_markers.is_first_enter(marker_idx)
            && matches!(marker.scope_id.kind(), Some(ScopeKind::Route))
        {
            if route_arm_event_ranges_for_scope(scope_markers, marker.scope_id).is_none() {
                return Some(ProgramSourceError::ProjectionRouteUnprojectable);
            }
            if let Some(error) =
                validate_passive_arm_child_projection(scope_markers, marker.scope_id, route_slot, 0)
            {
                return Some(error);
            }
            if let Some(error) =
                validate_passive_arm_child_projection(scope_markers, marker.scope_id, route_slot, 1)
            {
                return Some(error);
            }
            route_slot += 1;
        }
        marker_idx += 1;
    }
    None
}

const fn validate_passive_arm_child_projection(
    scope_markers: ScopeMarkerView<'_>,
    route: ScopeId,
    route_slot: usize,
    arm: u8,
) -> Option<ProgramSourceError> {
    let Some(child) = passive_route_child_scope(scope_markers, route, arm) else {
        return None;
    };
    if child.same(route) {
        return Some(ProgramSourceError::ProjectionRouteUnprojectable);
    }
    let Some((parent, parent_arm)) = route_parent_arm_for_scope(scope_markers, child) else {
        return Some(ProgramSourceError::ProjectionRouteUnprojectable);
    };
    if !parent.same(route) || parent_arm != arm {
        return Some(ProgramSourceError::ProjectionRouteUnprojectable);
    }
    let Some(child_slot) = route_scope_slot_for_scope(scope_markers, child) else {
        return Some(ProgramSourceError::ProjectionRouteUnprojectable);
    };
    if child_slot <= route_slot || child_slot >= u16::MAX as usize {
        return Some(ProgramSourceError::ProjectionRouteUnprojectable);
    }
    None
}