use std::fmt;
use axon_frontend::session::Payload;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ProtocolError {
PayloadMismatch { expected: Payload, got: Payload },
UnexpectedFrame {
cursor_kind: &'static str,
frame_kind: &'static str,
},
UnknownLabel { label: String, expected: Vec<String> },
CreditExhausted { payload: Payload, budget: u64 },
AlreadyComplete { frame_kind: &'static str },
MalformedFrame(String),
Transport(String),
NoInterruptArmed,
SignalMismatch { expected: Payload, got: Payload },
WatchdogBreach { bound: u32, actual: u32 },
DoubleResume,
}
impl fmt::Display for ProtocolError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ProtocolError::PayloadMismatch { expected, got } => write!(
f,
"payload mismatch: cursor expected `{expected}`, peer sent `{got}` \
(the connection is not dual to the declared role)"
),
ProtocolError::UnexpectedFrame { cursor_kind, frame_kind } => write!(
f,
"unexpected frame: cursor is at `{cursor_kind}`, peer sent `{frame_kind}` \
— the state machine has no transition for this input"
),
ProtocolError::UnknownLabel { label, expected } => write!(
f,
"unknown choice label `{label}` — declared labels: {}",
expected.join(", ")
),
ProtocolError::CreditExhausted { payload, budget } => write!(
f,
"credit exhausted on `send {payload}` at window n = 0 \
(budget = {budget})"
),
ProtocolError::AlreadyComplete { frame_kind } => write!(
f,
"dialogue already at `end`; peer sent `{frame_kind}` post-termination"
),
ProtocolError::MalformedFrame(detail) => write!(f, "malformed frame: {detail}"),
ProtocolError::Transport(detail) => write!(f, "transport error: {detail}"),
ProtocolError::NoInterruptArmed => write!(
f,
"signal fired but no interruptible region is armed (cursor not inside \
an `interrupt` body)"
),
ProtocolError::SignalMismatch { expected, got } => write!(
f,
"interrupt signal mismatch: region declares `on {expected}`, got `{got}`"
),
ProtocolError::WatchdogBreach { bound, actual } => write!(
f,
"WCET watchdog breach: reaction path took {actual} transitions, declared \
bound is {bound} (fail-closed)"
),
ProtocolError::DoubleResume => write!(
f,
"`resume` on an already-consumed one-shot continuation \
(linear-type violation)"
),
}
}
}
impl std::error::Error for ProtocolError {}
impl ProtocolError {
pub fn code(&self) -> &'static str {
match self {
ProtocolError::PayloadMismatch { .. } => "payload_mismatch",
ProtocolError::UnexpectedFrame { .. } => "unexpected_frame",
ProtocolError::UnknownLabel { .. } => "unknown_label",
ProtocolError::CreditExhausted { .. } => "credit_exhausted",
ProtocolError::AlreadyComplete { .. } => "already_complete",
ProtocolError::MalformedFrame(_) => "malformed_frame",
ProtocolError::Transport(_) => "transport",
ProtocolError::NoInterruptArmed => "no_interrupt_armed",
ProtocolError::SignalMismatch { .. } => "signal_mismatch",
ProtocolError::WatchdogBreach { .. } => "watchdog_breach",
ProtocolError::DoubleResume => "double_resume",
}
}
}