mecha10-core 0.6.2

Mecha10 core runtime and foundational types
Documentation
// System Message Types

use serde::{Deserialize, Serialize};
use std::collections::HashMap;

/// Health status of a node or system
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HealthStatus {
    /// Timestamp in microseconds since epoch
    pub timestamp: u64,

    /// Overall health level
    pub level: HealthLevel,

    /// Human-readable status message
    pub message: String,

    /// Additional diagnostic data (key-value pairs)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub diagnostics: Option<HashMap<String, String>>,
}

impl HealthStatus {
    /// Create a healthy status
    pub fn healthy() -> Self {
        Self {
            timestamp: crate::prelude::now_micros(),
            level: HealthLevel::Ok,
            message: "Operating normally".to_string(),
            diagnostics: None,
        }
    }

    /// Create a degraded status with a message
    pub fn degraded(message: impl Into<String>) -> Self {
        Self {
            timestamp: crate::prelude::now_micros(),
            level: HealthLevel::Degraded,
            message: message.into(),
            diagnostics: None,
        }
    }

    /// Create an unhealthy status with a message
    pub fn unhealthy(message: impl Into<String>) -> Self {
        Self {
            timestamp: crate::prelude::now_micros(),
            level: HealthLevel::Error,
            message: message.into(),
            diagnostics: None,
        }
    }

    /// Add diagnostic data
    pub fn with_diagnostic(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
        self.diagnostics
            .get_or_insert_with(HashMap::new)
            .insert(key.into(), value.into());
        self
    }

    /// Set a custom message
    pub fn with_message(mut self, message: impl Into<String>) -> Self {
        self.message = message.into();
        self
    }
}

/// Health level
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum HealthLevel {
    /// Everything is functioning normally
    Ok,

    /// Operating but with reduced performance
    Degraded,

    /// Not functioning properly
    Error,

    /// Cannot determine health status
    Unknown,
}

/// Node status information
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NodeStatus {
    /// Timestamp in microseconds since epoch
    pub timestamp: u64,

    /// Node name
    pub name: String,

    /// Current state
    pub state: NodeState,

    /// Uptime in seconds
    pub uptime: f64,

    /// CPU usage (0.0 to 1.0)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub cpu_usage: Option<f32>,

    /// Memory usage in bytes
    #[serde(skip_serializing_if = "Option::is_none")]
    pub memory_usage: Option<u64>,

    /// Message throughput (messages/second)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub message_rate: Option<f32>,

    /// Health status
    pub health: HealthStatus,
}

/// Node execution state
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum NodeState {
    /// Node is starting up
    Starting,

    /// Node is running normally
    Running,

    /// Node is paused
    Paused,

    /// Node is shutting down
    Stopping,

    /// Node has stopped
    Stopped,

    /// Node has crashed
    Crashed,
}

/// System command
///
/// Commands to control node execution
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SystemCommand {
    /// Timestamp in microseconds since epoch (optional, defaults to 0)
    #[serde(default)]
    pub timestamp: u64,

    /// Target node name (or "*" for all nodes)
    pub target: String,

    /// Command to execute
    pub command: Command,
}

/// Command types
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum Command {
    /// Start the node
    Start,

    /// Stop the node gracefully
    Stop,

    /// Pause execution
    Pause,

    /// Resume execution
    Resume,

    /// Restart the node
    Restart,

    /// Request health check
    HealthCheck,

    /// Reload configuration
    ReloadConfig,

    /// Shutdown the runtime
    Shutdown,
}

/// Generates a `SystemCommand` associated constructor that tags a specific
/// `Command` variant.
///
/// Every `SystemCommand` constructor has the same shape — stamp the current
/// timestamp, store the target, and set a fixed `Command` variant — so this
/// avoids repeating that boilerplate for each command kind.
macro_rules! system_command_ctor {
    ($(#[$meta:meta])* $name:ident, $variant:expr) => {
        $(#[$meta])*
        pub fn $name(target: impl Into<String>) -> Self {
            Self {
                timestamp: crate::prelude::now_micros(),
                target: target.into(),
                command: $variant,
            }
        }
    };
}

impl SystemCommand {
    system_command_ctor!(
        /// Create a start command
        start,
        Command::Start
    );

    system_command_ctor!(
        /// Create a stop command
        stop,
        Command::Stop
    );

    system_command_ctor!(
        /// Create a restart command
        restart,
        Command::Restart
    );

    system_command_ctor!(
        /// Create a health check request
        health_check,
        Command::HealthCheck
    );
}

#[cfg(test)]
mod system_command_tests {
    use super::*;

    #[test]
    fn start_targets_the_given_node_and_tags_the_start_command() {
        let cmd = SystemCommand::start("robot-1");
        assert_eq!(cmd.target, "robot-1");
        assert_eq!(cmd.command, Command::Start);
    }

    #[test]
    fn stop_targets_the_given_node_and_tags_the_stop_command() {
        let cmd = SystemCommand::stop("robot-1");
        assert_eq!(cmd.target, "robot-1");
        assert_eq!(cmd.command, Command::Stop);
    }

    #[test]
    fn restart_targets_the_given_node_and_tags_the_restart_command() {
        let cmd = SystemCommand::restart("robot-1");
        assert_eq!(cmd.target, "robot-1");
        assert_eq!(cmd.command, Command::Restart);
    }

    #[test]
    fn health_check_targets_the_given_node_and_tags_the_health_check_command() {
        let cmd = SystemCommand::health_check("robot-1");
        assert_eq!(cmd.target, "robot-1");
        assert_eq!(cmd.command, Command::HealthCheck);
    }

    #[test]
    fn each_constructor_accepts_any_impl_into_string_target() {
        let owned = SystemCommand::start(String::from("robot-2"));
        let borrowed = SystemCommand::start("robot-2");
        assert_eq!(owned.target, borrowed.target);
    }
}