use crate::node::NodeId;
use crate::predicate::PredicateError;
use polaris_system::param::{AccessMode, ErrorContext};
use std::any::TypeId;
use std::fmt;
use std::sync::Arc;
use std::time::Duration;
#[derive(Debug, Clone)]
#[non_exhaustive]
pub enum ExecutionError {
EmptyGraph,
NodeNotFound(NodeId),
NoNextNode(NodeId),
MissingPredicate(NodeId),
MissingBranch {
node: NodeId,
branch: &'static str,
},
SystemError(Arc<str>),
PredicateError(PredicateError),
MaxIterationsExceeded {
node: NodeId,
max: usize,
},
NoTerminationCondition(NodeId),
Timeout {
node: NodeId,
timeout: Duration,
},
Unimplemented(&'static str),
RecursionLimitExceeded {
depth: usize,
max: usize,
},
MissingDiscriminator(NodeId),
NoMatchingCase {
node: NodeId,
key: &'static str,
},
InternalError(String),
MiddlewareError {
middleware: String,
message: String,
},
GraphTimeout {
elapsed: Duration,
max: Duration,
},
}
impl fmt::Display for ExecutionError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ExecutionError::EmptyGraph => write!(f, "graph has no entry point"),
ExecutionError::NodeNotFound(id) => write!(f, "node not found: {id}"),
ExecutionError::NoNextNode(id) => write!(f, "no sequential edge from node: {id}"),
ExecutionError::MissingPredicate(id) => {
write!(f, "missing predicate on node: {id}")
}
ExecutionError::MissingBranch { node, branch } => {
write!(f, "missing {branch} branch on decision node: {node}")
}
ExecutionError::SystemError(msg) => write!(f, "system error: {msg}"),
ExecutionError::PredicateError(err) => write!(f, "predicate error: {err}"),
ExecutionError::MaxIterationsExceeded { node, max } => {
write!(f, "max iterations ({max}) exceeded on loop node: {node}")
}
ExecutionError::NoTerminationCondition(id) => {
write!(f, "loop node has no termination condition: {id}")
}
ExecutionError::Timeout { node, timeout } => {
write!(f, "system timed out after {:?} on node: {node}", timeout)
}
ExecutionError::Unimplemented(feature) => {
write!(f, "feature not implemented: {feature}")
}
ExecutionError::RecursionLimitExceeded { depth, max } => {
write!(
f,
"recursion limit exceeded: depth {depth} exceeds max {max}"
)
}
ExecutionError::MissingDiscriminator(id) => {
write!(f, "missing discriminator on switch node: {id}")
}
ExecutionError::NoMatchingCase { node, key } => {
write!(f, "no matching case for key '{key}' on switch node: {node}")
}
ExecutionError::InternalError(msg) => write!(f, "internal error: {msg}"),
ExecutionError::MiddlewareError {
middleware,
message,
} => {
write!(f, "middleware '{middleware}' failed: {message}")
}
ExecutionError::GraphTimeout { elapsed, max } => {
write!(
f,
"graph execution timed out after {elapsed:?} (max: {max:?})"
)
}
}
}
}
impl std::error::Error for ExecutionError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
ExecutionError::PredicateError(err) => Some(err),
_ => None,
}
}
}
#[derive(Debug, Clone)]
#[non_exhaustive]
pub enum ResourceValidationError {
MissingResource {
node: NodeId,
system_name: &'static str,
resource_type: &'static str,
type_id: TypeId,
access_mode: AccessMode,
},
MissingOutput {
node: NodeId,
system_name: &'static str,
output_type: &'static str,
type_id: TypeId,
},
}
impl fmt::Display for ResourceValidationError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ResourceValidationError::MissingResource {
node,
system_name,
resource_type,
access_mode,
..
} => {
let mode_str = match access_mode {
AccessMode::Read => "read",
AccessMode::Write => "write",
};
write!(
f,
"system '{system_name}' ({node}) requires {mode_str} access to missing resource: {resource_type}"
)
}
ResourceValidationError::MissingOutput {
node,
system_name,
output_type,
..
} => {
write!(
f,
"system '{system_name}' ({node}) requires missing output: {output_type}"
)
}
}
}
}
impl std::error::Error for ResourceValidationError {}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ErrorKind {
Execution,
ParamResolution,
}
impl fmt::Display for ErrorKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ErrorKind::Execution => write!(f, "execution"),
ErrorKind::ParamResolution => write!(f, "param_resolution"),
}
}
}
#[derive(Debug, Clone)]
pub struct CaughtError {
pub message: Arc<str>,
pub system_name: &'static str,
pub node_id: NodeId,
pub duration: Duration,
pub kind: ErrorKind,
}
impl fmt::Display for CaughtError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"system '{}' ({}) failed after {:?} [{}]: {}",
self.system_name, self.node_id, self.duration, self.kind, self.message
)
}
}
impl std::error::Error for CaughtError {}
impl ErrorContext for CaughtError {}
pub(crate) enum SystemOutcome {
Ok(Box<dyn core::any::Any + Send + Sync>),
Err(polaris_system::system::SystemError),
Timeout,
}