hibana 0.9.3

Session-typed choreographic programming for no_std Rust protocols, inspired by affine MPST
Documentation
use super::super::{
    BlobPtr, LaneSetView, LaneSteps, PackedLaneRange, PackedRollScopeRow, RoleCompiledCounts,
    RoleImageColumns, RoleImageRef, RoleLaneImage, RuntimeRoleFacts, RuntimeRoleFootprint,
};
use crate::global::typestate::{LocalDependency, LocalNode, PackedEventConflict};

#[inline(always)]
const fn compact_count(value: usize) -> u16 {
    if value > u16::MAX as usize {
        panic!("role descriptor fact overflow");
    }
    value as u16
}

impl RuntimeRoleFacts {
    const MAX_ROUTE_STACK_DEPTH: usize = 0;
    const LOCAL_STEP_COUNT: usize = 1;
    const ROUTE_SCOPE_COUNT: usize = 2;
    const ACTIVE_LANE_COUNT: usize = 3;
    const ENDPOINT_LANE_SLOT_COUNT: usize = 4;
    const LOGICAL_LANE_COUNT: usize = 5;

    #[inline(always)]
    pub(crate) const fn from_counts(counts: RoleCompiledCounts) -> Self {
        Self {
            words: [
                compact_count(counts.max_route_stack_depth),
                compact_count(counts.local_step_count),
                compact_count(counts.route_scope_count),
                compact_count(counts.active_lane_count),
                compact_count(counts.endpoint_lane_slot_count),
                compact_count(counts.logical_lane_count),
            ],
        }
    }

    #[inline(always)]
    pub(crate) const fn footprint(self) -> RuntimeRoleFootprint {
        RuntimeRoleFootprint {
            max_route_stack_depth: self.words[Self::MAX_ROUTE_STACK_DEPTH] as usize,
            local_step_count: self.words[Self::LOCAL_STEP_COUNT] as usize,
            route_scope_count: self.words[Self::ROUTE_SCOPE_COUNT] as usize,
            active_lane_count: self.words[Self::ACTIVE_LANE_COUNT] as usize,
            endpoint_lane_slot_count: self.words[Self::ENDPOINT_LANE_SLOT_COUNT] as usize,
            logical_lane_count: self.words[Self::LOGICAL_LANE_COUNT] as usize,
        }
    }
}

impl RoleImageRef {
    #[inline(always)]
    pub(crate) const fn new<const N: usize>(
        program: &'static crate::global::compiled::images::CompiledProgramRef,
        role: u8,
        facts: RuntimeRoleFacts,
        columns: RoleImageColumns,
        bytes: &'static [u8; N],
        active_lane_row: PackedLaneRange,
        first_active_lane: u16,
    ) -> Self {
        let blob = BlobPtr::from_array(bytes, columns.blob_len());
        Self {
            program,
            role,
            facts,
            columns,
            blob,
            active_lane_row,
            first_active_lane,
        }
    }

    #[inline(always)]
    pub(crate) const fn lanes(&self) -> RoleLaneImage<'_> {
        RoleLaneImage::new(&self.columns, self.blob)
    }

    #[inline(always)]
    pub(crate) const fn footprint(&self) -> RuntimeRoleFootprint {
        self.facts.footprint()
    }

    #[inline(always)]
    pub(crate) const fn local_step_count(&self) -> usize {
        self.footprint().local_step_count
    }

    #[inline(always)]
    pub(crate) const fn active_lane_set(&self) -> LaneSetView<'static> {
        let footprint = self.footprint();
        self.lanes()
            .lane_bit_view(self.active_lane_row, footprint.lane_word_count())
    }

    #[inline(always)]
    pub(crate) const fn resident_row_min_start(&self, idx: usize) -> Option<u16> {
        self.lanes().resident_row_min_start(idx)
    }

    #[inline(always)]
    pub(crate) const fn resident_row_lane_steps(
        &self,
        idx: usize,
        lane_idx: usize,
    ) -> Option<LaneSteps> {
        self.lanes().resident_row_lane_steps(idx, lane_idx)
    }

    #[inline(always)]
    pub(crate) const fn dependency_for_index(&self, current_idx: usize) -> Option<LocalDependency> {
        self.lanes().dependency_for_index(current_idx)
    }

    #[inline(always)]
    pub(crate) const fn event_conflict_for_index(&self, current_idx: usize) -> PackedEventConflict {
        self.lanes().event_conflict_for_index(current_idx)
    }

    #[inline(always)]
    pub(crate) const fn route_scope_conflict_by_slot(&self, slot: usize) -> PackedEventConflict {
        self.lanes().route_scope_conflict_by_slot(slot)
    }

    #[inline(always)]
    pub(crate) const fn route_commit_range_by_slot(&self, slot: usize, arm: u8) -> PackedLaneRange {
        self.lanes().route_commit_range_by_slot(slot, arm)
    }

    #[inline(always)]
    pub(crate) const fn route_commit_row_at(&self, idx: usize) -> PackedEventConflict {
        self.lanes().route_commit_row_at(idx)
    }

    #[inline(always)]
    pub(crate) const fn roll_scope_row(&self, slot: usize) -> Option<PackedRollScopeRow> {
        self.lanes().roll_scope_row(slot)
    }

    #[inline(always)]
    pub(crate) const fn route_scope_by_slot(
        &self,
        slot: usize,
    ) -> Option<crate::global::const_dsl::ScopeId> {
        self.lanes().route_scope_by_slot(slot)
    }

    #[inline(always)]
    pub(crate) const fn route_scope_reentry_by_slot(&self, slot: usize) -> bool {
        self.lanes().route_scope_reentry_by_slot(slot)
    }

    #[inline(always)]
    pub(crate) const fn passive_arm_child_ordinal_by_slot(
        &self,
        slot: usize,
        arm: u8,
    ) -> Option<u16> {
        self.lanes().passive_arm_child_ordinal_by_slot(slot, arm)
    }

    #[inline(always)]
    pub(crate) const fn route_arm_event_row_by_slot(
        &self,
        slot: usize,
        arm: u8,
    ) -> PackedLaneRange {
        self.lanes().route_arm_event_row_by_slot(slot, arm)
    }

    #[inline(always)]
    pub(crate) const fn local_step_lane(&self, step_idx: usize) -> Option<u8> {
        self.lanes().local_step_lane(step_idx)
    }

    #[inline(always)]
    pub(crate) const fn local_step_node(&self, step_idx: usize) -> Option<LocalNode> {
        if step_idx >= self.local_step_count() {
            None
        } else {
            self.lanes()
                .local_step_node(step_idx, self.role, self.program)
        }
    }

    #[inline(always)]
    pub(crate) const fn resident_row_lane_step_at(
        &self,
        idx: usize,
        lane_idx: usize,
        ordinal: usize,
    ) -> Option<u16> {
        self.lanes()
            .resident_row_lane_step_at(idx, lane_idx, ordinal)
    }

    #[inline(always)]
    pub(crate) const fn resident_row_lane_step_ordinal(
        &self,
        idx: usize,
        lane_idx: usize,
        step_idx: usize,
    ) -> Option<u16> {
        self.lanes()
            .resident_row_lane_step_ordinal(idx, lane_idx, step_idx)
    }

    #[inline(always)]
    pub(crate) const fn first_active_lane(&self) -> Option<usize> {
        if self.first_active_lane == u16::MAX {
            None
        } else {
            Some(self.first_active_lane as usize)
        }
    }

    #[inline(always)]
    pub(crate) const fn route_scope_arm_lane_set_by_slot(
        &self,
        slot: usize,
        arm: u8,
    ) -> Option<LaneSetView<'static>> {
        self.lanes()
            .route_scope_arm_lane_set_by_slot(slot, arm, self.footprint().lane_word_count())
    }

    #[inline(always)]
    pub(crate) const fn route_scope_offer_lane_set_by_slot(
        &self,
        slot: usize,
    ) -> Option<LaneSetView<'static>> {
        self.lanes()
            .route_scope_offer_lane_set_by_slot(slot, self.footprint().lane_word_count())
    }

    #[inline(always)]
    pub(crate) const fn route_arm_lane_first_step_by_slot(
        &self,
        slot: usize,
        arm: u8,
        lane: u8,
    ) -> Option<u16> {
        self.lanes().route_arm_lane_first_step_by_slot(
            slot,
            arm,
            lane,
            self.footprint().logical_lane_count,
        )
    }

    #[inline(always)]
    pub(crate) const fn route_arm_lane_last_step_by_slot(
        &self,
        slot: usize,
        arm: u8,
        lane: u8,
    ) -> Option<u16> {
        self.lanes().route_arm_lane_last_step_by_slot(
            slot,
            arm,
            lane,
            self.footprint().logical_lane_count,
        )
    }
}