use crate::coroutine::Fault;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum FaultClass {
Type,
Label,
Channel,
Verification,
Invoke,
Acquire,
Transfer,
Speculation,
Close,
Flow,
Progress,
OutputCondition,
Register,
ProgramCounter,
Buffer,
Credits,
}
#[must_use]
pub fn classify_fault(fault: &Fault) -> FaultClass {
match fault {
Fault::TypeViolation { .. } => FaultClass::Type,
Fault::UnknownLabel { .. } => FaultClass::Label,
Fault::ChannelClosed { .. } => FaultClass::Channel,
Fault::InvalidSignature { .. } | Fault::VerificationFailed { .. } => {
FaultClass::Verification
}
Fault::Invoke { .. } => FaultClass::Invoke,
Fault::Acquire { .. } => FaultClass::Acquire,
Fault::Transfer { .. } => FaultClass::Transfer,
Fault::Speculation { .. } => FaultClass::Speculation,
Fault::Close { .. } => FaultClass::Close,
Fault::FlowViolation { .. } => FaultClass::Flow,
Fault::NoProgressToken { .. } => FaultClass::Progress,
Fault::OutputCondition { .. } => FaultClass::OutputCondition,
Fault::OutOfRegisters => FaultClass::Register,
Fault::PcOutOfBounds => FaultClass::ProgramCounter,
Fault::BufferFull { .. } => FaultClass::Buffer,
Fault::OutOfCredits => FaultClass::Credits,
}
}
#[must_use]
pub fn fault_code(class: FaultClass) -> &'static str {
match class {
FaultClass::Type => "machine.fault.type",
FaultClass::Label => "machine.fault.label",
FaultClass::Channel => "machine.fault.channel",
FaultClass::Verification => "machine.fault.verification",
FaultClass::Invoke => "machine.fault.invoke",
FaultClass::Acquire => "machine.fault.acquire",
FaultClass::Transfer => "machine.fault.transfer",
FaultClass::Speculation => "machine.fault.speculation",
FaultClass::Close => "machine.fault.close",
FaultClass::Flow => "machine.fault.flow",
FaultClass::Progress => "machine.fault.progress",
FaultClass::OutputCondition => "machine.fault.output_condition",
FaultClass::Register => "machine.fault.register",
FaultClass::ProgramCounter => "machine.fault.pc",
FaultClass::Buffer => "machine.fault.buffer",
FaultClass::Credits => "machine.fault.credits",
}
}
#[must_use]
pub fn fault_code_of(fault: &Fault) -> &'static str {
fault_code(classify_fault(fault))
}
#[must_use]
pub fn transfer_fault_expect_endpoint_register(role: &str) -> Fault {
Fault::Transfer {
message: format!("{role}: transfer expects endpoint register"),
}
}
#[must_use]
pub fn transfer_fault_expect_nat_target(role: &str) -> Fault {
Fault::Transfer {
message: format!("{role}: transfer expects nat target coroutine id"),
}
}
#[must_use]
pub fn transfer_fault_target_id_out_of_range(role: &str) -> Fault {
Fault::Transfer {
message: format!("{role}: target id out of range"),
}
}
#[must_use]
pub fn transfer_fault_endpoint_not_owned() -> Fault {
Fault::Transfer {
message: "endpoint not owned".to_string(),
}
}
#[must_use]
pub fn transfer_fault_delegation_guard_violation(phase: &str) -> Fault {
Fault::Transfer {
message: format!("delegation guard violation {phase} transfer"),
}
}
#[must_use]
pub fn speculation_fault_disabled() -> Fault {
Fault::Speculation {
message: "speculation disabled".to_string(),
}
}
#[must_use]
pub fn speculation_fault_join_requires_active() -> Fault {
Fault::Speculation {
message: "join requires active speculation".to_string(),
}
}
#[must_use]
pub fn speculation_fault_abort_requires_active() -> Fault {
Fault::Speculation {
message: "abort requires active speculation".to_string(),
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::instr::Endpoint;
use crate::session::Edge;
use telltale_types::ValType;
#[test]
fn fault_codes_are_stable_for_representative_variants() {
let samples = [
Fault::TypeViolation {
expected: ValType::Unit,
actual: ValType::Nat,
message: "m".to_string(),
},
Fault::UnknownLabel {
label: "x".to_string(),
},
Fault::ChannelClosed {
endpoint: Endpoint {
sid: 1,
role: "A".to_string(),
},
},
Fault::VerificationFailed {
edge: Edge::new(1, "A", "B"),
message: "bad sig".to_string(),
},
Fault::OutOfCredits,
];
let codes: Vec<&str> = samples.iter().map(fault_code_of).collect();
assert_eq!(
codes,
vec![
"machine.fault.type",
"machine.fault.label",
"machine.fault.channel",
"machine.fault.verification",
"machine.fault.credits",
]
);
}
}