use sayiir_core::InvalidInstanceId;
use sayiir_core::error::{BoxError, BuildError, BuildErrors, CodecError, WorkflowError};
use sayiir_persistence::{BackendError, RunConflict};
#[derive(Debug, thiserror::Error)]
pub enum RuntimeError {
#[error(transparent)]
Workflow(#[from] WorkflowError),
#[error(transparent)]
Build(#[from] BuildErrors),
#[error(transparent)]
Backend(#[from] BackendError),
#[error(transparent)]
Codec(#[from] CodecError),
#[error(transparent)]
Task(BoxError),
#[error(transparent)]
Join(#[from] tokio::task::JoinError),
#[error("Workflow instance already exists: {0}")]
InstanceAlreadyExists(String),
#[error(transparent)]
InvalidInstanceId(#[from] InvalidInstanceId),
}
impl From<BoxError> for RuntimeError {
fn from(err: BoxError) -> Self {
match err.downcast::<CodecError>() {
Ok(codec_err) => Self::Codec(*codec_err),
Err(other) => Self::Task(other),
}
}
}
impl From<BuildError> for RuntimeError {
fn from(error: BuildError) -> Self {
Self::Build(BuildErrors::from(error))
}
}
impl From<RunConflict> for RuntimeError {
fn from(error: RunConflict) -> Self {
match error {
RunConflict::InvalidInstanceId(e) => Self::InvalidInstanceId(e),
RunConflict::AlreadyExists(id) => Self::InstanceAlreadyExists(id),
RunConflict::DefinitionMismatch { expected, found } => {
Self::Workflow(WorkflowError::DefinitionMismatch { expected, found })
}
RunConflict::Backend(e) => Self::Backend(e),
}
}
}
impl RuntimeError {
#[must_use]
pub fn is_timeout(&self) -> bool {
matches!(self, Self::Workflow(WorkflowError::TaskTimedOut { .. }))
}
#[must_use]
pub fn is_decode_error(&self) -> bool {
matches!(self, Self::Codec(CodecError::DecodeFailed { .. }))
}
}