mod source;
mod terms;
use core::marker::PhantomData;
pub use crate::global::Message;
pub(crate) use source::{ProgramSourceData, ProgramTerm};
pub(crate) const ROLE_DOMAIN_SIZE: u8 = 16;
const ROLE_INDEX_ERROR: &str = "role index must be < 16";
mod role_projection;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Msg<const LOGICAL_LABEL: u8, Payload>(PhantomData<Payload>);
#[derive(Clone, Copy)]
#[repr(u8)]
pub(crate) enum ProgramSourceError {
RouteArmAbsent,
RouteControllerMismatch,
RollBodyAbsent,
ParallelArmAbsent,
ParallelConflict,
ParallelAmbiguousEndpointSelector,
ReentryAmbiguousEndpointSelector,
ResolverIdOutOfDomain,
ResolverTargetNotRoute,
ProjectionRouteUnprojectable,
}
pub(crate) const fn panic_choreography_error(error: ProgramSourceError) -> ! {
match error {
ProgramSourceError::RouteArmAbsent => {
panic!("g::route arms must begin with a visible action")
}
ProgramSourceError::RouteControllerMismatch => {
panic!("intrinsic route arms use different first visible controllers")
}
ProgramSourceError::RollBodyAbsent => panic!("rolled body requires at least one step"),
ProgramSourceError::ParallelArmAbsent => {
panic!("g::par(left, right) arms require protocol steps")
}
ProgramSourceError::ParallelConflict => {
panic!("parallel lane ownership must be structurally disjoint")
}
ProgramSourceError::ParallelAmbiguousEndpointSelector => {
panic!("parallel endpoint operations must be unambiguous")
}
ProgramSourceError::ReentryAmbiguousEndpointSelector => {
panic!("rolled reentry endpoint operations must be unambiguous")
}
ProgramSourceError::ResolverIdOutOfDomain => {
panic!("route resolver id must be < u16::MAX")
}
ProgramSourceError::ResolverTargetNotRoute => {
panic!("route resolver can only be attached to a route")
}
ProgramSourceError::ProjectionRouteUnprojectable => panic!(concat!(
"Route unprojectable for this role: invalid, ambiguous endpoint operation, ",
"or ambiguous first-visible endpoint operation",
)),
}
}
#[derive(Clone, Copy)]
pub struct Program<Steps> {
steps: PhantomData<Steps>,
}
impl<Steps> Program<Steps> {
#[inline(always)]
pub(crate) const fn new() -> Self {
Self { steps: PhantomData }
}
}
pub(crate) const fn role_pair_contract_error<const FROM: u8, const TO: u8>() -> Option<&'static str>
{
if FROM >= ROLE_DOMAIN_SIZE || TO >= ROLE_DOMAIN_SIZE {
return Some(ROLE_INDEX_ERROR);
}
None
}
pub const fn send<const FROM: u8, const TO: u8, M>() -> Program<Send<FROM, TO, M>>
where
M: Message,
{
const {
if FROM >= ROLE_DOMAIN_SIZE || TO >= ROLE_DOMAIN_SIZE {
panic!("{}", ROLE_INDEX_ERROR);
}
}
Program::new()
}
impl<Steps> Program<Steps> {
pub const fn roll(self) -> Program<Roll<Steps>> {
let _ = self;
Program::new()
}
}
pub const fn seq<LeftSteps, RightSteps>(
left: Program<LeftSteps>,
right: Program<RightSteps>,
) -> Program<Seq<LeftSteps, RightSteps>> {
let _ = (left, right);
Program::new()
}
pub const fn route<LeftSteps, RightSteps>(
left: Program<LeftSteps>,
right: Program<RightSteps>,
) -> Program<Route<LeftSteps, RightSteps>> {
let _ = (left, right);
Program::new()
}
pub const fn par<LeftSteps, RightSteps>(
left: Program<LeftSteps>,
right: Program<RightSteps>,
) -> Program<Par<LeftSteps, RightSteps>> {
let _ = (left, right);
Program::new()
}
impl<LeftSteps, RightSteps> Program<Route<LeftSteps, RightSteps>> {
pub const fn resolve<const RESOLVER_ID: u16>(
self,
) -> Program<Resolve<Route<LeftSteps, RightSteps>, RESOLVER_ID>> {
if RESOLVER_ID == u16::MAX {
panic!("route resolver id must be < u16::MAX");
}
let _ = self;
Program::new()
}
}
struct ProgramProjection<Steps>(PhantomData<Steps>);
impl<Steps> ProgramProjection<Steps>
where
Steps: ProgramTerm,
{
const SOURCE: ProgramSourceData = <Steps as ProgramTerm>::PROGRAM_SOURCE;
pub(super) const SOURCE_EFF_LIST: &'static crate::global::const_dsl::EffList =
Self::SOURCE.eff_list();
const IMAGE: crate::global::compiled::lowering::CompiledProgramImage = {
let source = Self::SOURCE_EFF_LIST;
crate::global::compiled::lowering::CompiledProgramImage::scan_const(source)
};
const VALIDATION: () = {
if let Some(error) = Self::SOURCE.error() {
panic_choreography_error(error);
}
let source = Self::SOURCE_EFF_LIST;
Self::IMAGE.validate_projection_program();
if let Some(error) =
crate::global::compiled::lowering::projection_error_all_roles(&Self::IMAGE, source)
{
panic_choreography_error(error);
}
};
}
pub struct Send<const FROM: u8, const TO: u8, M>(PhantomData<M>);
pub struct Seq<Left, Right>(PhantomData<(Left, Right)>);
pub struct Route<Left, Right>(PhantomData<(Left, Right)>);
pub struct Par<Left, Right>(PhantomData<(Left, Right)>);
pub struct Resolve<Inner, const RESOLVER_ID: u16>(PhantomData<Inner>);
pub struct Roll<Inner>(PhantomData<Inner>);
pub(crate) fn project<const ROLE: u8, Steps>(
program: &Program<Steps>,
) -> crate::global::role_program::RoleProgram<ROLE>
where
Steps: ProgramTerm,
{
let _ = program;
let image = const {
if ROLE >= ROLE_DOMAIN_SIZE {
panic!("{}", ROLE_INDEX_ERROR);
}
role_projection::role_projection_image_for::<ROLE, Steps>()
};
crate::global::role_program::role_program_from_image(image)
}