use super::{
CommitDelta, CommitEventRow, CursorEndpoint, CursorInvariantError, PreparedRouteCommitRows,
RelocatableResidentLaneStep, SelectedRouteCommitRow, Transport, state_index_to_usize,
};
use crate::global::const_dsl::ReentryMark;
use crate::global::typestate::{EnabledEventCommit, StateIndex};
pub(crate) struct PreparedCommitDelta {
event: Option<CommitEventRow>,
selected_routes: PreparedRouteCommitRows,
lane_relocation: Option<RelocatableResidentLaneStep>,
cursor_after: StateIndex,
}
impl PreparedCommitDelta {
#[inline(always)]
fn from_preflighted(delta: CommitDelta, selected_routes: PreparedRouteCommitRows) -> Self {
Self {
event: delta.event(),
selected_routes,
lane_relocation: delta.lane_relocation(),
cursor_after: delta.cursor_after(),
}
}
#[inline(always)]
pub(crate) const fn event(&self) -> Option<CommitEventRow> {
self.event
}
#[inline(always)]
pub(crate) const fn selected_routes(&self) -> &PreparedRouteCommitRows {
&self.selected_routes
}
#[inline(always)]
pub(crate) const fn selected_route_lane(&self) -> Option<u8> {
self.selected_routes.selected_lane()
}
#[inline(always)]
pub(crate) const fn lane_relocation(&self) -> Option<RelocatableResidentLaneStep> {
self.lane_relocation
}
#[inline(always)]
pub(crate) const fn cursor_after(&self) -> StateIndex {
self.cursor_after
}
#[inline(always)]
pub(in crate::endpoint::kernel::core) fn take_selected_routes(
&mut self,
) -> PreparedRouteCommitRows {
self.selected_routes.take()
}
}
pub(crate) struct CommittedCommitDelta {
event: Option<CommitEventRow>,
selected_routes: PreparedRouteCommitRows,
}
impl CommittedCommitDelta {
#[inline(always)]
pub(in crate::endpoint::kernel::core) const fn from_applied(
event: Option<CommitEventRow>,
selected_routes: PreparedRouteCommitRows,
) -> Self {
Self {
event,
selected_routes,
}
}
#[inline(always)]
pub(crate) const fn event(&self) -> Option<CommitEventRow> {
self.event
}
#[inline(always)]
pub(crate) const fn selected_routes(&self) -> &PreparedRouteCommitRows {
&self.selected_routes
}
#[inline(always)]
pub(crate) const fn selected_route_lane(&self) -> Option<u8> {
self.selected_routes.selected_lane()
}
}
#[derive(Clone, Copy)]
pub(in crate::endpoint::kernel) struct CommitDeltaApplyPermit(());
impl CommitDeltaApplyPermit {
#[inline(always)]
pub(in crate::endpoint::kernel::core) const fn new() -> Self {
Self(())
}
}
impl<'r, const ROLE: u8, T> CursorEndpoint<'r, ROLE, T>
where
T: Transport + 'r,
{
pub(in crate::endpoint::kernel) fn preflight_commit_delta(
&self,
delta: &CommitDelta,
) -> Result<(), CursorInvariantError> {
if let Some(event) = delta.event() {
let idx = self
.cursor
.node_index_for_relocatable_step(event.progress_step())
.ok_or(CursorInvariantError::INVARIANT)?;
let mut selected_arm = |scope| {
if scope == event.scope() {
event.route_arm()
} else {
self.selected_arm_for_scope(scope)
}
};
let enabled = self.cursor.event_enabled(
idx,
crate::global::typestate::EventCommitMeta::new(
event.eff_index(),
event.event_label(),
event.event_origin(),
event.scope(),
event.route_arm(),
event.lane(),
),
&mut selected_arm,
)?;
if enabled.progress_step() != event.progress_step()
|| enabled.cursor_after() != delta.cursor_after()
{
return Err(CursorInvariantError::INVARIANT);
}
self.preflight_event_selected_route_chain(idx, delta)?;
} else if delta.selected_routes().is_empty() {
self.preflight_cursor_realign_delta(delta)?;
} else {
self.preflight_route_only_cursor_after(delta)?;
}
self.preflight_selected_route_rows(delta)?;
self.preflight_lane_relocation(delta.lane_relocation())?;
Ok(())
}
#[inline]
fn preflight_event_selected_route_chain(
&self,
event_idx: usize,
delta: &CommitDelta,
) -> Result<(), CursorInvariantError> {
let routes = delta.selected_routes();
let conflict = self.cursor.event_conflict_for_index(event_idx);
let Some(range) = self.cursor.route_commit_range_for_conflict(conflict) else {
return if conflict.to_conflict().is_none() && routes.is_empty() {
Ok(())
} else {
Err(CursorInvariantError::INVARIANT)
};
};
if routes.len() != range.len() {
return Err(CursorInvariantError::INVARIANT);
}
let mut idx = 0usize;
while idx < range.len() {
let Some(expected) = self
.cursor
.route_commit_row_at(range, idx)
.and_then(SelectedRouteCommitRow::from_resident_conflict)
else {
return Err(CursorInvariantError::INVARIANT);
};
let Some(row) = routes.get(&self.cursor, idx) else {
return Err(CursorInvariantError::INVARIANT);
};
if row.scope() != expected.scope() || row.selected_arm() != expected.selected_arm() {
return Err(CursorInvariantError::INVARIANT);
}
idx += 1;
}
Ok(())
}
#[inline]
fn preflight_cursor_realign_delta(
&self,
delta: &CommitDelta,
) -> Result<(), CursorInvariantError> {
let cursor_after = state_index_to_usize(delta.cursor_after());
if cursor_after >= self.cursor.local_steps_len() {
return Err(CursorInvariantError::INVARIANT);
}
Ok(())
}
#[inline]
fn preflight_selected_route_rows(
&self,
delta: &CommitDelta,
) -> Result<(), CursorInvariantError> {
let routes = delta.selected_routes();
let route_lane = if routes.is_empty() {
None
} else {
delta.selected_route_lane()
};
let mut idx = 0usize;
while idx < routes.len() {
let row = routes
.get(&self.cursor, idx)
.ok_or(CursorInvariantError::INVARIANT)?;
let lane = route_lane.ok_or(CursorInvariantError::INVARIANT)?;
self.preflight_selected_route_row(row, lane)?;
let mut prev_idx = 0usize;
while prev_idx < idx {
let prev = routes
.get(&self.cursor, prev_idx)
.ok_or(CursorInvariantError::INVARIANT)?;
if prev.scope() == row.scope() {
return Err(CursorInvariantError::INVARIANT);
}
prev_idx += 1;
}
idx += 1;
}
Ok(())
}
#[inline]
fn preflight_selected_route_row(
&self,
row: SelectedRouteCommitRow,
lane: u8,
) -> Result<(), CursorInvariantError> {
if row.is_empty() || row.selected_arm() > 1 {
return Err(CursorInvariantError::INVARIANT);
}
let lane_idx = lane as usize;
if lane_idx >= self.cursor.logical_lane_count() {
return Err(CursorInvariantError::INVARIANT);
}
let scope = row.scope();
if scope.is_none() || self.cursor.route_scope_slot(scope).is_none() {
return Err(CursorInvariantError::INVARIANT);
}
let scope_slot = self
.cursor
.route_scope_slot(scope)
.ok_or(CursorInvariantError::INVARIANT)?;
let reentry = if self.cursor.route_scope_reentry(scope) {
ReentryMark::Reentrant
} else {
ReentryMark::SinglePass
};
if self
.cursor
.passive_observer_arm_entry_index(scope, row.selected_arm())
.is_none()
&& self
.cursor
.controller_arm_entry_by_arm(scope, row.selected_arm())
.is_none()
{
return Err(CursorInvariantError::INVARIANT);
}
if let Some(selected) = self.selected_arm_for_scope(scope) {
if reentry.is_reentrant() && self.reentrant_selected_arm_complete(scope, selected) {
return Ok(());
}
if selected != row.selected_arm() {
return Err(CursorInvariantError::INVARIANT);
}
}
self.decision_state
.preflight_selected_route_commit(
lane_idx,
scope,
scope_slot,
row.selected_arm(),
reentry,
)
.ok_or(CursorInvariantError::INVARIANT)?;
Ok(())
}
#[inline]
fn preflight_lane_relocation(
&self,
step: Option<super::RelocatableResidentLaneStep>,
) -> Result<(), CursorInvariantError> {
let Some(step) = step else {
return Ok(());
};
self.cursor
.node_index_for_relocatable_step(step)
.ok_or(CursorInvariantError::INVARIANT)?;
Ok(())
}
#[inline(always)]
pub(in crate::endpoint::kernel) fn prepare_commit_delta(
&mut self,
delta: CommitDelta,
) -> Result<PreparedCommitDelta, CursorInvariantError> {
self.preflight_commit_delta(&delta)?;
let selected_routes = self
.route_commit_rows
.seal(delta.selected_route_rows_ref())
.map_err(|_| CursorInvariantError::INVARIANT)?;
Ok(PreparedCommitDelta::from_preflighted(
delta,
selected_routes,
))
}
#[inline]
pub(in crate::endpoint::kernel) fn prepare_enabled_event_commit_delta(
&mut self,
delta: CommitDelta,
enabled: EnabledEventCommit,
) -> Result<PreparedCommitDelta, CursorInvariantError> {
let event = delta.event().ok_or(CursorInvariantError::INVARIANT)?;
if event.progress_step() != enabled.progress_step()
|| delta.cursor_after() != enabled.cursor_after()
{
return Err(CursorInvariantError::INVARIANT);
}
let idx = enabled.event_index().as_usize();
self.preflight_event_selected_route_chain(idx, &delta)?;
self.preflight_selected_route_rows(&delta)?;
self.preflight_lane_relocation(delta.lane_relocation())?;
let selected_routes = self
.route_commit_rows
.seal(delta.selected_route_rows_ref())
.map_err(|_| CursorInvariantError::INVARIANT)?;
Ok(PreparedCommitDelta::from_preflighted(
delta,
selected_routes,
))
}
#[inline(always)]
pub(in crate::endpoint::kernel) fn commit_cursor_realign_index(
&mut self,
idx: usize,
) -> Result<(), CursorInvariantError> {
if idx > u16::MAX as usize {
return Err(CursorInvariantError::INVARIANT);
}
let delta = CommitDelta::cursor_only(StateIndex::from_usize(idx));
let delta = self.prepare_commit_delta(delta)?;
self.commit_prepared_delta(delta);
Ok(())
}
}