mod source;
mod terms;
use core::marker::PhantomData;
pub use crate::global::Message;
pub(crate) use source::{
ProgramShape, ProgramSourceData, ProgramSourceNode, SourceRouteResolver, checked_source_count,
};
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 {
RouteControllerMismatch,
ReceiveLaneCausalityConflict,
ParallelAmbiguousEndpointSelector,
ReentryAmbiguousEndpointSelector,
ProjectionRouteUnprojectable,
}
pub(crate) const fn panic_choreography_error(error: ProgramSourceError) -> ! {
match error {
ProgramSourceError::RouteControllerMismatch => {
panic!("route arms use different first visible controllers")
}
ProgramSourceError::ReceiveLaneCausalityConflict => {
panic!("receive lane sender change requires a causal handoff or exclusive route arms")
}
ProgramSourceError::ParallelAmbiguousEndpointSelector => {
panic!("parallel endpoint operations must be unambiguous")
}
ProgramSourceError::ReentryAmbiguousEndpointSelector => {
panic!("rolled reentry endpoint operations must be unambiguous")
}
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 const fn send<const FROM: u8, const TO: u8, M>() -> Program<Send<FROM, TO, M>>
where
M: Message,
M::Payload: crate::transport::wire::WireEncode + crate::transport::wire::WirePayload,
{
const {
if FROM == TO
&& <M::Payload as crate::transport::wire::WirePayload>::SCHEMA_ID
!= <() as crate::transport::wire::WirePayload>::SCHEMA_ID
{
panic!("self-role actions require the unit payload");
}
}
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>> {
let _ = self;
Program::new()
}
}
struct ProgramProjection<Steps, const CAPACITY: usize>(PhantomData<Steps>);
impl<Steps, const CAPACITY: usize> ProgramProjection<Steps, CAPACITY>
where
Steps: ProgramShape,
{
const SOURCE: ProgramSourceData<CAPACITY> = ProgramSourceData::lower::<Steps>();
pub(super) const SOURCE_EFF_LIST: &'static crate::global::const_dsl::EffList<CAPACITY> =
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: () = {
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: ProgramShape,
{
let _ = program;
let image = const {
let required_rows = <Steps as ProgramShape>::SOURCE_ROW_COUNT;
if required_rows <= 8 {
role_projection::role_projection_image_for::<ROLE, Steps, 8>()
} else if required_rows <= 32 {
role_projection::role_projection_image_for::<ROLE, Steps, 32>()
} else if required_rows <= 128 {
role_projection::role_projection_image_for::<ROLE, Steps, 128>()
} else if required_rows <= 512 {
role_projection::role_projection_image_for::<ROLE, Steps, 512>()
} else if required_rows <= 2048 {
role_projection::role_projection_image_for::<ROLE, Steps, 2048>()
} else if required_rows <= 8192 {
role_projection::role_projection_image_for::<ROLE, Steps, 8192>()
} else if required_rows <= 32768 {
role_projection::role_projection_image_for::<ROLE, Steps, 32768>()
} else if required_rows <= 65535 {
role_projection::role_projection_image_for::<ROLE, Steps, 65535>()
} else {
panic!("choreography source exceeds compact descriptor domain")
}
};
crate::global::role_program::role_program_from_image(image)
}