hibana 0.8.0

Const-projected Affine Multiparty Session Types for choreography-first Rust protocols
Documentation
use super::{Par, Policy, ProgramSourceData, ProgramSourceError, ProgramTerm, Route, Send, Seq};
use crate::global::LoopControlMeaning;
use crate::global::steps::{PolicyEligible, RoleLaneMask};

#[derive(Clone, Copy)]
struct CycleRouteValidation {
    is_cycle: bool,
    error: Option<ProgramSourceError>,
}

const fn is_binary_cycle_route(
    left: Option<LoopControlMeaning>,
    right: Option<LoopControlMeaning>,
) -> CycleRouteValidation {
    match (left, right) {
        (Some(LoopControlMeaning::Continue), Some(LoopControlMeaning::Break)) => {
            CycleRouteValidation {
                is_cycle: true,
                error: None,
            }
        }
        (Some(_), Some(_)) => CycleRouteValidation {
            is_cycle: false,
            error: Some(ProgramSourceError::LoopRouteArmOrder),
        },
        (Some(_), None) | (None, Some(_)) => CycleRouteValidation {
            is_cycle: false,
            error: Some(ProgramSourceError::LoopRouteArmPair),
        },
        _ => CycleRouteValidation {
            is_cycle: false,
            error: None,
        },
    }
}

impl<const FROM: u8, const TO: u8, M, const LANE: u8> ProgramTerm for Send<FROM, TO, M, LANE>
where
    M: crate::global::Message,
{
    const PROGRAM_SOURCE: ProgramSourceData = {
        let control = <M as crate::global::MessageRuntime>::CONTROL;
        ProgramSourceData::from_parts(
            crate::global::const_dsl::const_send_typed::<FROM, TO, M, LANE>(),
            RoleLaneMask::empty()
                .with_role(FROM, LANE)
                .with_role(TO, LANE),
            false,
            LoopControlMeaning::from_control_spec(control).is_some(),
        )
    };
}

impl<Left, Right> ProgramTerm for Seq<Left, Right>
where
    Left: ProgramTerm,
    Right: ProgramTerm,
{
    const PROGRAM_SOURCE: ProgramSourceData =
        <Left as ProgramTerm>::PROGRAM_SOURCE.seq(<Right as ProgramTerm>::PROGRAM_SOURCE);
}

impl<Left, Right> ProgramTerm for Route<Left, Right>
where
    Left: ProgramTerm,
    Right: ProgramTerm,
{
    const PROGRAM_SOURCE: ProgramSourceData = {
        let left = <Left as ProgramTerm>::PROGRAM_SOURCE;
        let right = <Right as ProgramTerm>::PROGRAM_SOURCE;
        let left_head = left.route_head();
        let right_head = right.route_head();
        let mut route_error = ProgramSourceData::merge_error(left_head.error, right_head.error);
        if left_head.label == right_head.label {
            route_error = ProgramSourceData::merge_error(
                route_error,
                Some(ProgramSourceError::RouteDuplicateLabel),
            );
        }
        if left_head.controller != right_head.controller {
            route_error = ProgramSourceData::merge_error(
                route_error,
                Some(ProgramSourceError::RouteControllerMismatch),
            );
        }
        let cycle = is_binary_cycle_route(left_head.cycle_meaning, right_head.cycle_meaning);
        route_error = ProgramSourceData::merge_error(route_error, cycle.error);
        left.route_with_controller(right, left_head.controller, cycle.is_cycle, route_error)
    };
}

impl<Left, Right> ProgramTerm for Par<Left, Right>
where
    Left: ProgramTerm,
    Right: ProgramTerm,
{
    const PROGRAM_SOURCE: ProgramSourceData =
        { <Left as ProgramTerm>::PROGRAM_SOURCE.par(<Right as ProgramTerm>::PROGRAM_SOURCE) };
}

impl<Steps, const POLICY_ID: u16> ProgramTerm for Policy<Steps, POLICY_ID>
where
    Steps: ProgramTerm + PolicyEligible,
{
    const PROGRAM_SOURCE: ProgramSourceData =
        <Steps as ProgramTerm>::PROGRAM_SOURCE.with_policy(POLICY_ID);
}