sandl 0.1.0

A framework for building parallel execution engines with dependency management, type-safe method dispatch, and event observation.
Documentation
use crate::Value;

pub type Result<T> = std::result::Result<T, Error>;

#[derive(thiserror::Error, Debug)]
pub enum Error {
    #[error("Layer '{0}' not found")]
    LayerNotFound(String),

    #[error("Layer '{0}' already exists")]
    LayerAlreadyExists(String),

    #[error("Method '{method}' not found in layer '{layer}'")]
    MethodNotFound { method: String, layer: String },

    #[error("Method '{0}' has not been bound in layer '{1}'")]
    MethodNotBound(String, String),

    #[error("Method execution failed in slice '{slice}', layer '{layer}', method '{method}'")]
    MethodExecutionFailed {
        slice: String,
        layer: String,
        method: String,
        args: Value,
        #[source]
        cause: Box<Error>,
    },

    #[error("Execution error: {0}")]
    ExecutionError(String),

    #[error("Configuration error: {0}")]
    ConfigError(String),
}

impl Error {
    pub fn with_context(
        self,
        slice: impl Into<String>,
        layer: impl Into<String>,
        method: impl Into<String>,
        args: Value,
    ) -> Self {
        Error::MethodExecutionFailed {
            slice: slice.into(),
            layer: layer.into(),
            method: method.into(),
            args,
            cause: Box::new(self),
        }
    }

    pub fn root_cause(&self) -> &Error {
        match self {
            Error::MethodExecutionFailed { cause, .. } => cause.root_cause(),
            other => other,
        }
    }

    pub fn execution_context(&self) -> Option<(&str, &str, &str, &Value)> {
        match self {
            Error::MethodExecutionFailed {
                slice,
                layer,
                method,
                args,
                ..
            } => Some((slice, layer, method, args)),
            _ => None,
        }
    }

    pub fn is_execution_error(&self) -> bool {
        matches!(self, Error::MethodExecutionFailed { .. })
    }

    pub fn message(&self) -> String {
        match self {
            Error::MethodExecutionFailed { cause, .. } => cause.message(),
            Error::ExecutionError(msg) => msg.clone(),
            other => other.to_string(),
        }
    }
}