hibana 0.9.6

Choreography-derived runtime enforcement kernel for no_std Rust multiparty protocols
Documentation
use super::super::{
    ColumnRange, LANE_DOMAIN_SIZE, ROLE_IMAGE_CONFLICT_STRIDE, ROLE_IMAGE_DEPENDENCY_STRIDE,
    ROLE_IMAGE_EVENT_STRIDE, ROLE_IMAGE_LANE_RANGE_STRIDE, ROLE_IMAGE_LANE_STRIDE,
    ROLE_IMAGE_ROLL_SCOPE_STRIDE, ROLE_IMAGE_ROUTE_ARM_LANE_STEP_STRIDE,
    ROLE_IMAGE_ROUTE_ARM_STRIDE, ROLE_IMAGE_ROUTE_SCOPE_STRIDE, ROLE_IMAGE_U16_STRIDE,
    RoleImageColumns, RoleImagePlan, RuntimeRoleFacts, lane_byte_count,
};
use super::projection;
use crate::global::const_dsl::{EffList, ScopeKind};

pub(super) struct RoleImageColumnCounts {
    pub(super) dependency_rows: usize,
    pub(super) conflict_rows: usize,
    pub(super) resident_boundaries: usize,
    pub(super) lane_bits: usize,
    pub(super) route_arm_lane_steps: usize,
    pub(super) route_commit_rows: usize,
    pub(super) roll_scopes: usize,
}

struct RouteImagePlanRouteFacts {
    lane_bits: usize,
    route_arm_lane_steps: usize,
    route_commit_rows: usize,
}

impl RoleImagePlan {
    #[inline(always)]
    pub(crate) const fn blob_len(&self) -> usize {
        self.columns.blob_len()
    }

    pub(crate) const fn from_program<const E: usize>(
        eff_list: &EffList<E>,
        facts: RuntimeRoleFacts,
        role: u8,
    ) -> Self {
        let counts = RoleImageColumnCounts::from_program(
            eff_list,
            facts.footprint().logical_lane_count,
            role,
        );
        Self {
            columns: counts.columns(facts),
        }
    }
}

impl RoleImageColumnCounts {
    const fn column_at(offset: usize, len: usize, stride: usize) -> (ColumnRange, usize) {
        let column = ColumnRange::new(offset, len, stride);
        (column, column.end_offset(stride))
    }

    pub(super) const fn columns(self, facts: RuntimeRoleFacts) -> RoleImageColumns {
        let footprint = facts.footprint();
        let local_len = footprint.local_step_count;
        let route_scope_len = footprint.route_scope_count;
        let route_arm_len = route_scope_len * 2;

        let (events, offset) = Self::column_at(0, local_len, ROLE_IMAGE_EVENT_STRIDE);
        let (lanes, offset) = Self::column_at(offset, local_len, ROLE_IMAGE_LANE_STRIDE);
        let (dependencies, offset) =
            Self::column_at(offset, self.dependency_rows, ROLE_IMAGE_DEPENDENCY_STRIDE);
        let (conflicts, offset) =
            Self::column_at(offset, self.conflict_rows, ROLE_IMAGE_CONFLICT_STRIDE);
        let (route_scopes, offset) =
            Self::column_at(offset, route_scope_len, ROLE_IMAGE_ROUTE_SCOPE_STRIDE);
        let (route_scope_conflicts, offset) =
            Self::column_at(offset, route_scope_len, ROLE_IMAGE_CONFLICT_STRIDE);
        let (route_arms, offset) =
            Self::column_at(offset, route_arm_len, ROLE_IMAGE_ROUTE_ARM_STRIDE);
        let (resident_boundaries, offset) =
            Self::column_at(offset, self.resident_boundaries, ROLE_IMAGE_U16_STRIDE);
        let (lane_bits, offset) = Self::column_at(offset, self.lane_bits, ROLE_IMAGE_LANE_STRIDE);
        let (route_arm_lane_rows, offset) =
            Self::column_at(offset, route_arm_len, ROLE_IMAGE_LANE_RANGE_STRIDE);
        let (route_offer_lane_rows, offset) =
            Self::column_at(offset, route_scope_len, ROLE_IMAGE_LANE_RANGE_STRIDE);
        let (route_arm_lane_step_rows, offset) = Self::column_at(
            offset,
            self.route_arm_lane_steps,
            ROLE_IMAGE_ROUTE_ARM_LANE_STEP_STRIDE,
        );
        let (route_commit_ranges, offset) =
            Self::column_at(offset, route_arm_len, ROLE_IMAGE_LANE_RANGE_STRIDE);
        let (route_commit_rows, _) =
            Self::column_at(offset, self.route_commit_rows, ROLE_IMAGE_CONFLICT_STRIDE);
        let (roll_scopes, _) = Self::column_at(
            route_commit_rows.end_offset(ROLE_IMAGE_CONFLICT_STRIDE),
            self.roll_scopes,
            ROLE_IMAGE_ROLL_SCOPE_STRIDE,
        );
        RoleImageColumns {
            events,
            lanes,
            dependencies,
            conflicts,
            route_scopes,
            route_scope_conflicts,
            route_arms,
            resident_boundaries,
            lane_bits,
            route_arm_lane_rows,
            route_offer_lane_rows,
            route_arm_lane_step_rows,
            route_commit_ranges,
            route_commit_rows,
            roll_scopes,
        }
    }
}

impl RoleImageColumnCounts {
    pub(super) const fn from_program<const E: usize>(
        eff_list: &EffList<E>,
        logical_lane_count: usize,
        role: u8,
    ) -> Self {
        if logical_lane_count == 0 || logical_lane_count > LANE_DOMAIN_SIZE {
            panic!("role logical lane domain invalid");
        }
        let markers = eff_list.scope_markers();
        let has_route = projection::scope_markers_contain_kind(markers, ScopeKind::Route);
        let mut local_step_count = 0usize;
        let mut dependency_rows = 0usize;
        let mut conflict_rows = 0usize;
        let mut max_lane_plus_one = 0usize;
        let mut dependencies = projection::DependencyCursor::new(eff_list, role);
        let mut idx = 0usize;
        while idx < eff_list.len() {
            let atom = eff_list.atom_at(idx);
            if atom.from == role || atom.to == role {
                let lane_plus_one = atom.lane as usize + 1;
                if lane_plus_one > logical_lane_count {
                    panic!("local event lane outside role logical domain");
                }
                if lane_plus_one > max_lane_plus_one {
                    max_lane_plus_one = lane_plus_one;
                }
                if !dependencies
                    .next(idx, atom.lane, local_step_count)
                    .is_none()
                {
                    dependency_rows += 1;
                }
                if has_route && !projection::route_conflict_for_eff(markers, idx).is_none() {
                    conflict_rows += 1;
                }
                local_step_count += 1;
            }
            idx += 1;
        }
        let resident_rows = Self::resident_row_count(eff_list, role);
        let route_facts = Self::route_facts(eff_list, role);
        let roll_scopes = Self::roll_scope_count(eff_list, role);
        let active_lane_bits = lane_byte_count(max_lane_plus_one);
        let resident_boundaries = if resident_rows == 0 {
            0
        } else {
            resident_rows + 1
        };
        Self {
            dependency_rows,
            conflict_rows,
            resident_boundaries,
            lane_bits: active_lane_bits + route_facts.lane_bits,
            route_arm_lane_steps: route_facts.route_arm_lane_steps,
            route_commit_rows: route_facts.route_commit_rows,
            roll_scopes,
        }
    }

    const fn resident_row_count<const E: usize>(eff_list: &EffList<E>, role: u8) -> usize {
        let mut rows = projection::ResidentRowCursor::new(eff_list, role);
        let mut row_count = 0usize;
        while rows.next().is_some() {
            row_count += 1;
        }
        row_count
    }

    const fn route_facts<const E: usize>(
        eff_list: &EffList<E>,
        role: u8,
    ) -> RouteImagePlanRouteFacts {
        let markers = eff_list.scope_markers();
        if !projection::scope_markers_contain_kind(markers, ScopeKind::Route) {
            return RouteImagePlanRouteFacts {
                lane_bits: 0,
                route_arm_lane_steps: 0,
                route_commit_rows: 0,
            };
        }
        let mut facts = RouteImagePlanRouteFacts {
            lane_bits: 0,
            route_arm_lane_steps: 0,
            route_commit_rows: 0,
        };
        let mut marker_idx = 0usize;
        while marker_idx < markers.len() {
            let marker = markers.at(marker_idx);
            if markers.is_first_enter(marker_idx)
                && matches!(marker.scope_id.kind(), Some(ScopeKind::Route))
            {
                let scope = marker.scope_id;
                let Some(ranges) = projection::route_arm_ranges(markers, scope) else {
                    panic!("route scope missing binary arm ranges");
                };
                let mut arm = 0usize;
                let mut arm_lane_bits = [0usize; 2];
                while arm < 2 {
                    let (start, end) = ranges[arm];
                    let lanes =
                        projection::LocalLaneFacts::for_eff_range(eff_list, role, start, end);
                    arm_lane_bits[arm] = lanes.lane_bit_len();
                    facts.lane_bits += lanes.lane_bit_len();
                    facts.route_arm_lane_steps += lanes.relation_count();
                    facts.route_commit_rows += projection::route_commit_row_count(
                        markers,
                        eff_list.len(),
                        scope,
                        arm as u8,
                    );
                    arm += 1;
                }
                let offer_lane_bits = if arm_lane_bits[0] > arm_lane_bits[1] {
                    arm_lane_bits[0]
                } else {
                    arm_lane_bits[1]
                };
                facts.lane_bits += offer_lane_bits;
            }
            marker_idx += 1;
        }
        facts
    }

    const fn roll_scope_count<const E: usize>(eff_list: &EffList<E>, role: u8) -> usize {
        let markers = eff_list.scope_markers();
        if !projection::scope_markers_contain_kind(markers, ScopeKind::Roll) {
            return 0;
        }
        let mut count = 0usize;
        let mut marker_idx = 0usize;
        while marker_idx < markers.len() {
            let marker = markers.at(marker_idx);
            if markers.is_first_enter(marker_idx)
                && matches!(marker.scope_id.kind(), Some(ScopeKind::Roll))
            {
                let end_eff =
                    projection::scope_segment_end(markers, marker_idx, Some(eff_list.len()));
                let row = projection::local_step_range_for_eff_range(
                    eff_list,
                    marker.offset(),
                    end_eff,
                    role,
                );
                if !row.is_absent_or_zero_len() {
                    count += 1;
                }
            }
            marker_idx += 1;
        }
        count
    }
}