hibana 0.9.3

Session-typed choreographic programming for no_std Rust protocols, inspired by affine MPST
Documentation
use super::columns::{
    PROGRAM_IMAGE_ATOM_STRIDE, PROGRAM_IMAGE_INTRINSIC_ROUTE_DECISION_TAG,
    PROGRAM_IMAGE_INTRINSIC_ROUTE_ROLE, PROGRAM_IMAGE_ROUTE_RESOLVER_STRIDE, ProgramColumnRange,
    ProgramImageColumns, ProgramImageFacts, ROUTE_ORDINAL_BYTES, insert_route_ordinal,
};
use crate::{
    eff::{EffAtom, EffKind},
    global::compiled::lowering::CompiledProgramImage,
    global::const_dsl::{
        EffList, INTRINSIC_ROUTE_RESOLVER_ID, RouteResolver, ScopeEvent, ScopeId, ScopeKind,
        parallel_arm_ranges_from_enter, route_arm_ranges_from_first_enter,
    },
};

pub(crate) struct ProgramImageBytes<const N: usize> {
    bytes: [u8; N],
}

impl<const N: usize> ProgramImageBytes<N> {
    #[inline(always)]
    const fn empty() -> Self {
        Self { bytes: [0; N] }
    }

    #[inline(always)]
    pub(crate) const fn compiled_ref(
        &'static self,
        image: &CompiledProgramImage,
        columns: ProgramImageColumns,
    ) -> super::CompiledProgramRef {
        let facts = ProgramImageFacts::from_image(image);
        super::CompiledProgramRef::compact(facts, columns, &self.bytes)
    }

    #[inline(always)]
    const fn write_u8(&mut self, offset: usize, value: u8) {
        if offset >= self.bytes.len() {
            crate::invariant();
        }
        self.bytes[offset] = value;
    }

    #[inline(always)]
    const fn write_u16(&mut self, offset: usize, value: u16) {
        self.write_u8(offset, value as u8);
        self.write_u8(offset + 1, (value >> 8) as u8);
    }

    #[inline(always)]
    const fn column_offset(column: ProgramColumnRange, row: usize, stride: usize) -> usize {
        if row >= column.len as usize {
            crate::invariant();
        }
        column.offset as usize + row * stride
    }

    #[inline(always)]
    const fn write_atom(
        &mut self,
        column: ProgramColumnRange,
        row: usize,
        offset: usize,
        atom: EffAtom,
    ) {
        if offset > u16::MAX as usize {
            crate::invariant();
        }
        let out = Self::column_offset(column, row, PROGRAM_IMAGE_ATOM_STRIDE);
        self.write_u16(out, offset as u16);
        self.write_u8(out + 2, atom.from);
        self.write_u8(out + 3, atom.to);
        self.write_u8(out + 4, atom.label);
        self.write_u8(out + 5, atom.origin.packed_bits());
        self.write_u8(out + 6, atom.lane);
    }

    const fn write_route_resolver(
        &mut self,
        column: ProgramColumnRange,
        row: usize,
        scope: ScopeId,
        controller_role: Option<u8>,
        decision: Option<(RouteResolver, u8)>,
    ) {
        let out = Self::column_offset(column, row, PROGRAM_IMAGE_ROUTE_RESOLVER_STRIDE);
        self.write_u16(out, scope.raw());
        let (resolver_id, decision_tag) = match decision {
            Some((resolver, tag)) => {
                let resolver_id = match resolver {
                    RouteResolver::Dynamic { resolver_id, .. } => resolver_id,
                    RouteResolver::Intrinsic => INTRINSIC_ROUTE_RESOLVER_ID,
                };
                (resolver_id, tag)
            }
            None => (
                INTRINSIC_ROUTE_RESOLVER_ID,
                PROGRAM_IMAGE_INTRINSIC_ROUTE_DECISION_TAG,
            ),
        };
        self.write_u16(out + 2, resolver_id);
        self.write_u8(
            out + 4,
            match controller_role {
                Some(role) => role,
                None => PROGRAM_IMAGE_INTRINSIC_ROUTE_ROLE,
            },
        );
        self.write_u8(out + 5, decision_tag);
    }

    #[inline(always)]
    const fn route_resolver_decision(
        eff_list: &EffList,
        route_scope: ScopeId,
        route_enter_marker_idx: usize,
    ) -> Option<(RouteResolver, u8)> {
        let scope_markers = eff_list.scope_markers();
        if route_enter_marker_idx >= scope_markers.len() {
            return None;
        }
        let route_marker = scope_markers[route_enter_marker_idx];
        if !matches!(route_marker.event, ScopeEvent::Enter)
            || !matches!(route_marker.scope_id.kind(), Some(ScopeKind::Route))
            || !route_marker.scope_id.same(route_scope)
        {
            return None;
        }
        match eff_list.resolver_for_scope(route_scope) {
            Some(resolver @ RouteResolver::Dynamic { .. }) => Some((resolver, 0)),
            Some(RouteResolver::Intrinsic) | None => None,
        }
    }

    #[inline(always)]
    const fn unique_controller_role(mask: u16) -> Option<u8> {
        if mask == 0 || (mask & (mask - 1)) != 0 {
            return None;
        }
        let mut role = 0u8;
        while role < u16::BITS as u8 {
            if (mask & (1u16 << role)) != 0 {
                return Some(role);
            }
            role += 1;
        }
        None
    }

    #[inline(always)]
    const fn route_controller_role(
        eff_list: &EffList,
        route_enter_marker_idx: usize,
    ) -> Option<u8> {
        let scope_markers = eff_list.scope_markers();
        if route_enter_marker_idx >= scope_markers.len() {
            return None;
        }
        let (_, arm0_start, arm0_end, _, arm1_start, arm1_end) =
            route_arm_ranges_from_first_enter(scope_markers, route_enter_marker_idx);
        let mask = Self::first_visible_controller_mask(eff_list, arm0_start, arm0_end)
            | Self::first_visible_controller_mask(eff_list, arm1_start, arm1_end);
        Self::unique_controller_role(mask)
    }

    const fn first_visible_controller_mask(eff_list: &EffList, start: usize, end: usize) -> u16 {
        let markers = eff_list.scope_markers();
        let mut idx = start;
        while idx < end && idx < eff_list.len() {
            if let Some(route_enter) = Self::route_enter_at(markers, idx, end) {
                let (_, arm0_start, arm0_end, _, arm1_start, arm1_end) =
                    route_arm_ranges_from_first_enter(markers, route_enter);
                return Self::first_visible_controller_mask(eff_list, arm0_start, arm0_end)
                    | Self::first_visible_controller_mask(eff_list, arm1_start, arm1_end);
            }
            if let Some(par_enter) = Self::parallel_enter_at(markers, idx, end) {
                let Some((arm0_start, arm0_end, arm1_start, arm1_end)) =
                    parallel_arm_ranges_from_enter(markers, par_enter)
                else {
                    return 0;
                };
                return Self::first_visible_controller_mask(eff_list, arm0_start, arm0_end)
                    | Self::first_visible_controller_mask(eff_list, arm1_start, arm1_end);
            }
            if let Some(atom) = Self::atom_at(eff_list, idx) {
                if atom.from >= crate::g::ROLE_DOMAIN_SIZE {
                    return 0;
                }
                return 1u16 << atom.from;
            }
            idx += 1;
        }
        0
    }

    #[inline(always)]
    const fn atom_at(eff_list: &EffList, idx: usize) -> Option<EffAtom> {
        if idx >= eff_list.len() {
            return None;
        }
        let node = eff_list.node_at(idx);
        if matches!(node.kind, EffKind::Atom) {
            Some(node.atom_data())
        } else {
            None
        }
    }

    const fn route_enter_at(
        markers: &[crate::global::const_dsl::ScopeMarker],
        start: usize,
        end: usize,
    ) -> Option<usize> {
        let mut idx = 0usize;
        while idx < markers.len() {
            let marker = markers[idx];
            if marker.offset() == start
                && matches!(marker.event, ScopeEvent::Enter)
                && matches!(marker.scope_id.kind(), Some(ScopeKind::Route))
                && Self::first_enter_for_scope(markers, idx)
            {
                let (_, _, _, _, _, arm1_end) = route_arm_ranges_from_first_enter(markers, idx);
                if arm1_end <= end {
                    return Some(idx);
                }
            }
            idx += 1;
        }
        None
    }

    const fn first_enter_for_scope(
        markers: &[crate::global::const_dsl::ScopeMarker],
        marker_idx: usize,
    ) -> bool {
        let marker = markers[marker_idx];
        let mut idx = 0usize;
        while idx < marker_idx {
            let candidate = markers[idx];
            if matches!(candidate.event, ScopeEvent::Enter)
                && candidate.scope_id.same(marker.scope_id)
            {
                return false;
            }
            idx += 1;
        }
        true
    }

    const fn parallel_enter_at(
        markers: &[crate::global::const_dsl::ScopeMarker],
        start: usize,
        end: usize,
    ) -> Option<usize> {
        let mut idx = 0usize;
        while idx < markers.len() {
            let marker = markers[idx];
            if marker.offset() == start
                && matches!(marker.event, ScopeEvent::Enter)
                && matches!(marker.scope_id.kind(), Some(ScopeKind::Parallel))
                && matches!(
                    parallel_arm_ranges_from_enter(markers, idx),
                    Some((_, _, _, right_end)) if right_end <= end
                )
            {
                return Some(idx);
            }
            idx += 1;
        }
        None
    }

    #[inline(always)]
    pub(crate) const fn from_capacity_bucket(
        eff_list: &EffList,
        columns: ProgramImageColumns,
    ) -> Self {
        if columns.blob_len() > N {
            return Self::empty();
        }
        Self::from_image(eff_list, columns)
    }

    pub(crate) const fn from_image(eff_list: &EffList, columns: ProgramImageColumns) -> Self {
        let projected_len = columns.blob_len();
        if projected_len > N {
            crate::invariant();
        }
        let markers = eff_list.scope_markers();
        if projected_len > u16::MAX as usize {
            crate::invariant();
        }

        let mut out = Self::empty();
        let mut atom_row = 0usize;
        let mut idx = 0usize;
        while idx < eff_list.len() {
            if let Some(atom) = Self::atom_at(eff_list, idx) {
                out.write_atom(columns.atoms, atom_row, idx, atom);
                atom_row += 1;
            }
            idx += 1;
        }

        let mut route_row = 0usize;
        let mut seen_route_ordinals = [0u8; ROUTE_ORDINAL_BYTES];
        idx = 0;
        while idx < markers.len() {
            let marker = markers[idx];
            if matches!(marker.event, ScopeEvent::Enter)
                && matches!(marker.scope_id.kind(), Some(ScopeKind::Route))
            {
                let ordinal = marker.scope_id.local_ordinal() as usize;
                if !insert_route_ordinal(&mut seen_route_ordinals, ordinal) {
                    idx += 1;
                    continue;
                }
                let controller = Self::route_controller_role(eff_list, idx);
                let decision = Self::route_resolver_decision(eff_list, marker.scope_id, idx);
                out.write_route_resolver(
                    columns.route_resolvers,
                    route_row,
                    marker.scope_id,
                    controller,
                    decision,
                );
                route_row += 1;
            }
            idx += 1;
        }
        out
    }
}