use crate::{
control::cap::mint::CapShot,
eff::{self, EffIndex},
global::{
compiled::images::ControlSemanticKind,
const_dsl::{CompactScopeId, PolicyMode, ScopeId, ScopeKind},
},
};
pub(crate) const ARM_SHARED: u8 = 0xFF;
pub(crate) const MAX_FIRST_RECV_DISPATCH: usize = 16;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) struct ScopeRegion {
pub scope_id: ScopeId,
pub kind: ScopeKind,
pub start: usize,
pub end: usize,
pub range: u16,
pub nest: u16,
pub linger: bool,
pub controller_role: Option<u8>,
}
#[repr(transparent)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub(crate) struct StateIndex(u16);
impl StateIndex {
pub(crate) const MAX: 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) {
panic!("state index overflow");
}
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_max(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 JumpReason {
PassiveObserverBranch,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) struct JumpError {
pub iterations: u32,
pub idx: usize,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) enum PassiveArmNavigation {
WithinArm { entry: StateIndex },
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) enum LocalAction {
Send {
eff_index: EffIndex,
peer: u8,
label: u8,
frame_label: u8,
resource: Option<u8>,
is_control: bool,
shot: Option<CapShot>,
policy: PolicyMode,
lane: u8,
},
Recv {
eff_index: EffIndex,
peer: u8,
label: u8,
frame_label: u8,
resource: Option<u8>,
is_control: bool,
shot: Option<CapShot>,
policy: PolicyMode,
lane: u8,
},
Local {
eff_index: EffIndex,
label: u8,
frame_label: u8,
resource: Option<u8>,
is_control: bool,
shot: Option<CapShot>,
policy: PolicyMode,
lane: u8,
},
Terminate,
}
const LOCAL_ACTION_STATIC_POLICY_ID: u16 = u16::MAX;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum PackedLocalAction {
Send {
eff_index: EffIndex,
peer: u8,
label: u8,
frame_label: u8,
resource: Option<u8>,
is_control: bool,
shot: Option<CapShot>,
policy_id: u16,
lane: u8,
},
Recv {
eff_index: EffIndex,
peer: u8,
label: u8,
frame_label: u8,
resource: Option<u8>,
is_control: bool,
shot: Option<CapShot>,
policy_id: u16,
lane: u8,
},
Local {
eff_index: EffIndex,
label: u8,
frame_label: u8,
resource: Option<u8>,
is_control: bool,
shot: Option<CapShot>,
policy_id: u16,
lane: u8,
},
Terminate,
}
#[inline(always)]
const fn encode_policy_id(policy: PolicyMode) -> u16 {
match policy.dynamic_policy_id() {
Some(policy_id) => policy_id,
None => LOCAL_ACTION_STATIC_POLICY_ID,
}
}
#[inline(always)]
const fn decode_policy(policy_id: u16, scope: CompactScopeId) -> PolicyMode {
if policy_id == LOCAL_ACTION_STATIC_POLICY_ID {
PolicyMode::Static
} else {
PolicyMode::Dynamic { policy_id, scope }
}
}
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 { .. })
}
#[inline(always)]
pub(crate) const fn is_jump(&self) -> bool {
false
}
#[inline(always)]
pub(crate) const fn jump_reason(&self) -> Option<JumpReason> {
None
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) struct LocalNode {
action: PackedLocalAction,
next: StateIndex,
scope: CompactScopeId,
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: ControlSemanticKind) -> u8 {
semantic.packed_bits() << Self::FLAG_SEMANTIC_SHIFT
}
#[inline(always)]
const fn decode_semantic(flags: u8) -> ControlSemanticKind {
ControlSemanticKind::from_packed_bits(
(flags & Self::FLAG_SEMANTIC_MASK) >> Self::FLAG_SEMANTIC_SHIFT,
)
}
#[inline(always)]
const fn flags(is_choice_determinant: bool, semantic: ControlSemanticKind) -> u8 {
let mut flags = Self::encode_semantic(semantic);
if is_choice_determinant {
flags |= Self::FLAG_CHOICE_DETERMINANT;
}
flags
}
#[allow(clippy::too_many_arguments)]
pub(crate) const fn send(
eff_index: EffIndex,
peer: u8,
label: u8,
frame_label: u8,
resource: Option<u8>,
is_control: bool,
shot: Option<CapShot>,
policy: PolicyMode,
lane: u8,
semantic: ControlSemanticKind,
next: StateIndex,
scope: ScopeId,
_loop_scope: Option<ScopeId>,
route_arm: Option<u8>,
is_choice_determinant: bool,
) -> Self {
Self {
action: PackedLocalAction::Send {
eff_index,
peer,
label,
frame_label,
resource,
is_control,
shot,
policy_id: encode_policy_id(policy),
lane,
},
next,
scope: CompactScopeId::from_scope_id(scope),
route_arm_raw: Self::encode_route_arm(route_arm),
flags: Self::flags(is_choice_determinant, semantic),
}
}
#[allow(clippy::too_many_arguments)]
pub(crate) const fn recv(
eff_index: EffIndex,
peer: u8,
label: u8,
frame_label: u8,
resource: Option<u8>,
is_control: bool,
shot: Option<CapShot>,
policy: PolicyMode,
lane: u8,
semantic: ControlSemanticKind,
next: StateIndex,
scope: ScopeId,
_loop_scope: Option<ScopeId>,
route_arm: Option<u8>,
is_choice_determinant: bool,
) -> Self {
Self {
action: PackedLocalAction::Recv {
eff_index,
peer,
label,
frame_label,
resource,
is_control,
shot,
policy_id: encode_policy_id(policy),
lane,
},
next,
scope: CompactScopeId::from_scope_id(scope),
route_arm_raw: Self::encode_route_arm(route_arm),
flags: Self::flags(is_choice_determinant, semantic),
}
}
#[allow(clippy::too_many_arguments)]
pub(crate) const fn local(
eff_index: EffIndex,
label: u8,
frame_label: u8,
resource: Option<u8>,
is_control: bool,
shot: Option<CapShot>,
policy: PolicyMode,
lane: u8,
semantic: ControlSemanticKind,
next: StateIndex,
scope: ScopeId,
_loop_scope: Option<ScopeId>,
route_arm: Option<u8>,
is_choice_determinant: bool,
) -> Self {
Self {
action: PackedLocalAction::Local {
eff_index,
label,
frame_label,
resource,
is_control,
shot,
policy_id: encode_policy_id(policy),
lane,
},
next,
scope: CompactScopeId::from_scope_id(scope),
route_arm_raw: Self::encode_route_arm(route_arm),
flags: Self::flags(is_choice_determinant, semantic),
}
}
pub(crate) const fn terminal(index: StateIndex) -> Self {
Self {
action: PackedLocalAction::Terminate,
next: index,
scope: CompactScopeId::none(),
route_arm_raw: Self::ROUTE_ARM_NONE,
flags: 0,
}
}
#[inline(always)]
pub(crate) const fn action(&self) -> LocalAction {
match self.action {
PackedLocalAction::Send {
eff_index,
peer,
label,
frame_label,
resource,
is_control,
shot,
policy_id,
lane,
} => LocalAction::Send {
eff_index,
peer,
label,
frame_label,
resource,
is_control,
shot,
policy: decode_policy(policy_id, self.scope),
lane,
},
PackedLocalAction::Recv {
eff_index,
peer,
label,
frame_label,
resource,
is_control,
shot,
policy_id,
lane,
} => LocalAction::Recv {
eff_index,
peer,
label,
frame_label,
resource,
is_control,
shot,
policy: decode_policy(policy_id, self.scope),
lane,
},
PackedLocalAction::Local {
eff_index,
label,
frame_label,
resource,
is_control,
shot,
policy_id,
lane,
} => LocalAction::Local {
eff_index,
label,
frame_label,
resource,
is_control,
shot,
policy: decode_policy(policy_id, self.scope),
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.to_scope_id()
}
#[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 control_semantic(&self) -> ControlSemanticKind {
Self::decode_semantic(self.flags)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct SendMeta {
pub eff_index: EffIndex,
pub peer: u8,
pub label: u8,
pub frame_label: u8,
pub resource: Option<u8>,
pub semantic: ControlSemanticKind,
pub is_control: bool,
pub next: usize,
pub scope: ScopeId,
pub route_arm: Option<u8>,
pub shot: Option<CapShot>,
policy: PolicyMode,
pub lane: u8,
}
impl SendMeta {
pub(crate) const fn new(
eff_index: EffIndex,
peer: u8,
label: u8,
frame_label: u8,
resource: Option<u8>,
semantic: ControlSemanticKind,
is_control: bool,
next: usize,
scope: ScopeId,
route_arm: Option<u8>,
shot: Option<CapShot>,
policy: PolicyMode,
lane: u8,
) -> Self {
Self {
eff_index,
peer,
label,
frame_label,
resource,
semantic,
is_control,
next,
scope,
route_arm,
shot,
policy,
lane,
}
}
#[inline(always)]
pub(crate) const fn policy(&self) -> PolicyMode {
self.policy
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) struct RecvMeta {
pub eff_index: EffIndex,
pub peer: u8,
pub label: u8,
pub frame_label: u8,
pub resource: Option<u8>,
pub semantic: ControlSemanticKind,
pub is_control: bool,
pub next: usize,
pub scope: ScopeId,
pub route_arm: Option<u8>,
pub is_choice_determinant: bool,
pub shot: Option<CapShot>,
pub policy: PolicyMode,
pub lane: u8,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) struct LocalMeta {
pub eff_index: EffIndex,
pub label: u8,
pub frame_label: u8,
pub resource: Option<u8>,
pub semantic: ControlSemanticKind,
pub is_control: bool,
pub next: usize,
pub scope: ScopeId,
pub route_arm: Option<u8>,
pub shot: Option<CapShot>,
pub policy: PolicyMode,
pub lane: u8,
}
pub(crate) const fn as_state_index(idx: usize) -> StateIndex {
StateIndex::from_usize(idx)
}
pub(crate) const fn state_index_to_usize(index: StateIndex) -> usize {
index.as_usize()
}