use crate::{
eff::{self, EffIndex, EventOrigin},
global::{
compiled::images::EventSemanticKind,
const_dsl::{ReentryMark, ScopeId, ScopeKind},
},
};
mod dependency;
pub(crate) use dependency::{LocalDependency, PackedLocalDependency};
mod meta;
pub(crate) use meta::{EventCommitMeta, LocalMeta, RecvMeta, SendMeta, state_index_to_usize};
mod passive_child;
pub(crate) use passive_child::PassiveArmChildFact;
pub(crate) const ARM_SHARED: u8 = 0xFF;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) struct PackedEventConflict(u16);
impl PackedEventConflict {
const ABSENT_RAW: u16 = u16::MAX;
const ARM_BITS: u16 = 1;
const ROUTE_MASK: u16 = (1 << 12) - 1;
const ROUTE_REENTRY_BIT: u16 = 1 << 13;
const NO_CONFLICT_BIT: u16 = 1 << 14;
pub(crate) const MAX_CHAIN_DEPTH: usize = eff::meta::MAX_EFF_NODES + 1;
#[inline(always)]
pub(crate) const fn none() -> Self {
Self(Self::ABSENT_RAW)
}
#[inline(always)]
pub(crate) const fn from_raw(raw: u16) -> Self {
Self(raw)
}
#[inline(always)]
pub(crate) const fn raw(self) -> u16 {
self.0
}
#[inline(always)]
pub(crate) const fn is_none(self) -> bool {
self.0 == Self::ABSENT_RAW || (self.0 & Self::NO_CONFLICT_BIT) != 0
}
#[inline(always)]
pub(crate) const fn route_arm(scope: ScopeId, arm: u8) -> Self {
if scope.is_none() || !matches!(scope.kind(), Some(ScopeKind::Route)) {
crate::invariant();
}
if arm > 1 {
crate::invariant();
}
let ordinal = scope.local_ordinal();
if ordinal > Self::ROUTE_MASK {
crate::invariant();
}
Self((ordinal << Self::ARM_BITS) | arm as u16)
}
#[inline(always)]
pub(crate) const fn with_route_reentry(self, mark: ReentryMark) -> Self {
match mark {
ReentryMark::SinglePass => {
if self.0 == Self::ABSENT_RAW
|| self.0 == (Self::NO_CONFLICT_BIT | Self::ROUTE_REENTRY_BIT)
{
Self::none()
} else {
Self(self.0 & !Self::ROUTE_REENTRY_BIT)
}
}
ReentryMark::Reentrant => {
if self.0 == Self::ABSENT_RAW {
Self(Self::NO_CONFLICT_BIT | Self::ROUTE_REENTRY_BIT)
} else {
Self(self.0 | Self::ROUTE_REENTRY_BIT)
}
}
}
}
#[inline(always)]
pub(crate) const fn route_reentry(self) -> bool {
self.0 != Self::ABSENT_RAW && (self.0 & Self::ROUTE_REENTRY_BIT) != 0
}
#[inline(always)]
pub(crate) const fn from_conflict(conflict: LocalConflict) -> Self {
match conflict {
LocalConflict::RouteArm { scope, arm } => Self::route_arm(scope, arm),
LocalConflict::Unconditional | LocalConflict::SharedRoute => Self::none(),
}
}
#[inline(always)]
pub(crate) const fn to_conflict(self) -> Option<LocalConflict> {
if self.is_none() {
return None;
}
let arm = (self.0 & 1) as u8;
let ordinal = (self.0 >> Self::ARM_BITS) & Self::ROUTE_MASK;
Some(LocalConflict::RouteArm {
scope: ScopeId::route(ordinal),
arm,
})
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) enum LocalConflict {
Unconditional,
SharedRoute,
RouteArm { scope: ScopeId, arm: u8 },
}
impl LocalConflict {
#[inline(always)]
pub(crate) const fn route_arm(scope: ScopeId, arm: Option<u8>) -> Self {
match arm {
Some(arm) => Self::RouteArm { scope, arm },
None => Self::SharedRoute,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) enum LocalDependencyState {
InactiveByConflict,
Satisfied,
Blocked,
}
impl LocalDependencyState {
#[inline(always)]
pub(crate) const fn allows_event(self) -> bool {
!matches!(self, Self::Blocked)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) struct RouteScopeRows {
scope: ScopeId,
start: usize,
end: usize,
reentry: ReentryMark,
}
impl RouteScopeRows {
#[inline(always)]
pub(crate) const fn new(
scope: ScopeId,
start: usize,
end: usize,
reentry: ReentryMark,
) -> Option<Self> {
if scope.is_none()
|| !matches!(scope.kind(), Some(ScopeKind::Route))
|| start >= end
|| end > u16::MAX as usize
{
None
} else {
Some(Self {
scope,
start,
end,
reentry,
})
}
}
#[inline(always)]
pub(crate) const fn scope(self) -> ScopeId {
self.scope
}
#[inline(always)]
pub(crate) const fn start(self) -> usize {
self.start
}
#[inline(always)]
pub(crate) const fn end(self) -> usize {
self.end
}
#[inline(always)]
pub(crate) const fn reentry(self) -> bool {
self.reentry.is_reentrant()
}
}
#[repr(transparent)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub(crate) struct StateIndex(u16);
impl StateIndex {
pub(crate) const ABSENT: Self = Self(u16::MAX);
#[inline(always)]
pub(crate) const fn new(raw: u16) -> Self {
Self(raw)
}
#[inline(always)]
pub(crate) const fn from_usize(idx: usize) -> Self {
if idx > (u16::MAX as usize) {
crate::invariant();
}
Self(idx as u16)
}
#[inline(always)]
pub(crate) const fn raw(self) -> u16 {
self.0
}
#[inline(always)]
pub(crate) const fn as_usize(self) -> usize {
self.0 as usize
}
#[inline(always)]
pub(crate) const fn is_absent(self) -> bool {
self.0 == u16::MAX
}
}
pub(crate) const MAX_STATES: usize = eff::meta::MAX_EFF_NODES + 1;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) enum LocalAction {
Send {
eff_index: EffIndex,
peer: u8,
label: u8,
frame_label: u8,
origin: EventOrigin,
lane: u8,
},
Recv {
eff_index: EffIndex,
peer: u8,
label: u8,
frame_label: u8,
origin: EventOrigin,
lane: u8,
},
Local {
eff_index: EffIndex,
label: u8,
frame_label: u8,
origin: EventOrigin,
lane: u8,
},
Terminate,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum PackedLocalAction {
Send {
eff_index: EffIndex,
peer: u8,
label: u8,
frame_label: u8,
origin: EventOrigin,
lane: u8,
},
Recv {
eff_index: EffIndex,
peer: u8,
label: u8,
frame_label: u8,
origin: EventOrigin,
lane: u8,
},
Local {
eff_index: EffIndex,
label: u8,
frame_label: u8,
origin: EventOrigin,
lane: u8,
},
Terminate,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) struct LocalAtomFacts {
pub(crate) eff_index: EffIndex,
pub(crate) label: u8,
pub(crate) frame_label: u8,
pub(crate) origin: EventOrigin,
pub(crate) lane: u8,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) enum RouteChoiceMark {
Ordinary,
Determinant,
}
impl RouteChoiceMark {
#[inline(always)]
pub(crate) const fn is_determinant(self) -> bool {
matches!(self, Self::Determinant)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) struct LocalNodeMeta {
pub(crate) semantic: EventSemanticKind,
pub(crate) next: StateIndex,
pub(crate) scope: ScopeId,
pub(crate) route_arm: Option<u8>,
pub(crate) choice: RouteChoiceMark,
}
impl LocalAction {
#[inline(always)]
pub(crate) const fn is_send(&self) -> bool {
matches!(self, Self::Send { .. })
}
#[inline(always)]
pub(crate) const fn is_recv(&self) -> bool {
matches!(self, Self::Recv { .. })
}
#[inline(always)]
pub(crate) const fn is_terminal(&self) -> bool {
matches!(self, Self::Terminate)
}
#[inline(always)]
pub(crate) const fn is_local_action(&self) -> bool {
matches!(self, Self::Local { .. })
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) struct LocalNode {
action: PackedLocalAction,
next: StateIndex,
scope: ScopeId,
route_arm_raw: u8,
flags: u8,
}
impl LocalNode {
const ROUTE_ARM_NONE: u8 = u8::MAX;
const FLAG_CHOICE_DETERMINANT: u8 = 1 << 0;
const FLAG_SEMANTIC_SHIFT: u8 = 1;
const FLAG_SEMANTIC_MASK: u8 = 0b11 << Self::FLAG_SEMANTIC_SHIFT;
#[inline(always)]
const fn encode_route_arm(route_arm: Option<u8>) -> u8 {
match route_arm {
Some(arm) => arm,
None => Self::ROUTE_ARM_NONE,
}
}
#[inline(always)]
const fn decode_route_arm(raw: u8) -> Option<u8> {
if raw == Self::ROUTE_ARM_NONE {
None
} else {
Some(raw)
}
}
#[inline(always)]
const fn encode_semantic(semantic: EventSemanticKind) -> u8 {
semantic.packed_bits() << Self::FLAG_SEMANTIC_SHIFT
}
#[inline(always)]
const fn decode_semantic(flags: u8) -> EventSemanticKind {
EventSemanticKind::from_packed_bits(
(flags & Self::FLAG_SEMANTIC_MASK) >> Self::FLAG_SEMANTIC_SHIFT,
)
}
#[inline(always)]
const fn flags(choice: RouteChoiceMark, semantic: EventSemanticKind) -> u8 {
let mut flags = Self::encode_semantic(semantic);
if choice.is_determinant() {
flags |= Self::FLAG_CHOICE_DETERMINANT;
}
flags
}
pub(crate) const fn send(peer: u8, facts: LocalAtomFacts, meta: LocalNodeMeta) -> Self {
Self {
action: PackedLocalAction::Send {
eff_index: facts.eff_index,
peer,
label: facts.label,
frame_label: facts.frame_label,
origin: facts.origin,
lane: facts.lane,
},
next: meta.next,
scope: meta.scope,
route_arm_raw: Self::encode_route_arm(meta.route_arm),
flags: Self::flags(meta.choice, meta.semantic),
}
}
pub(crate) const fn recv(peer: u8, facts: LocalAtomFacts, meta: LocalNodeMeta) -> Self {
Self {
action: PackedLocalAction::Recv {
eff_index: facts.eff_index,
peer,
label: facts.label,
frame_label: facts.frame_label,
origin: facts.origin,
lane: facts.lane,
},
next: meta.next,
scope: meta.scope,
route_arm_raw: Self::encode_route_arm(meta.route_arm),
flags: Self::flags(meta.choice, meta.semantic),
}
}
pub(crate) const fn local(facts: LocalAtomFacts, meta: LocalNodeMeta) -> Self {
Self {
action: PackedLocalAction::Local {
eff_index: facts.eff_index,
label: facts.label,
frame_label: facts.frame_label,
origin: facts.origin,
lane: facts.lane,
},
next: meta.next,
scope: meta.scope,
route_arm_raw: Self::encode_route_arm(meta.route_arm),
flags: Self::flags(meta.choice, meta.semantic),
}
}
pub(crate) const fn terminal(index: StateIndex) -> Self {
Self {
action: PackedLocalAction::Terminate,
next: index,
scope: ScopeId::none(),
route_arm_raw: Self::ROUTE_ARM_NONE,
flags: 0,
}
}
pub(crate) const fn action(&self) -> LocalAction {
match self.action {
PackedLocalAction::Send {
eff_index,
peer,
label,
frame_label,
origin,
lane,
} => LocalAction::Send {
eff_index,
peer,
label,
frame_label,
origin,
lane,
},
PackedLocalAction::Recv {
eff_index,
peer,
label,
frame_label,
origin,
lane,
} => LocalAction::Recv {
eff_index,
peer,
label,
frame_label,
origin,
lane,
},
PackedLocalAction::Local {
eff_index,
label,
frame_label,
origin,
lane,
} => LocalAction::Local {
eff_index,
label,
frame_label,
origin,
lane,
},
PackedLocalAction::Terminate => LocalAction::Terminate,
}
}
#[inline(always)]
pub(crate) const fn next(&self) -> StateIndex {
self.next
}
#[inline(always)]
pub(crate) const fn scope(&self) -> ScopeId {
self.scope
}
#[inline(always)]
pub(crate) const fn route_arm(&self) -> Option<u8> {
Self::decode_route_arm(self.route_arm_raw)
}
#[inline(always)]
pub(crate) const fn is_choice_determinant(&self) -> bool {
(self.flags & Self::FLAG_CHOICE_DETERMINANT) != 0
}
#[inline(always)]
pub(crate) const fn choice_mark(&self) -> RouteChoiceMark {
if self.is_choice_determinant() {
RouteChoiceMark::Determinant
} else {
RouteChoiceMark::Ordinary
}
}
#[inline(always)]
pub(crate) const fn event_semantic(&self) -> EventSemanticKind {
Self::decode_semantic(self.flags)
}
}