From 87044a747b47bd83249d61a45842c7f7b2eae56d Mon Sep 17 00:00:00 2001 From: soryu Date: Sun, 11 Jan 2026 05:52:14 +0000 Subject: Contract system --- makima/src/daemon/task/state.rs | 161 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 161 insertions(+) create mode 100644 makima/src/daemon/task/state.rs (limited to 'makima/src/daemon/task/state.rs') diff --git a/makima/src/daemon/task/state.rs b/makima/src/daemon/task/state.rs new file mode 100644 index 0000000..ca5fc01 --- /dev/null +++ b/makima/src/daemon/task/state.rs @@ -0,0 +1,161 @@ +//! Task state machine. + +use std::fmt; + +/// Task execution state. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum TaskState { + /// Task received, preparing overlay. + Initializing, + /// Overlay ready, starting container. + Starting, + /// Container running. + Running, + /// Container paused. + Paused, + /// Waiting for sibling or resource. + Blocked, + /// Task completed successfully. + Completed, + /// Task failed with error. + Failed, + /// Task interrupted by user. + Interrupted, +} + +impl TaskState { + /// Check if a state transition is valid. + pub fn can_transition_to(&self, target: TaskState) -> bool { + use TaskState::*; + + matches!( + (self, target), + // From Initializing + (Initializing, Starting) + | (Initializing, Failed) + | (Initializing, Interrupted) + // From Starting + | (Starting, Running) + | (Starting, Failed) + | (Starting, Interrupted) + // From Running + | (Running, Paused) + | (Running, Blocked) + | (Running, Completed) + | (Running, Failed) + | (Running, Interrupted) + // From Paused + | (Paused, Running) + | (Paused, Interrupted) + | (Paused, Failed) + // From Blocked + | (Blocked, Running) + | (Blocked, Failed) + | (Blocked, Interrupted) + ) + } + + /// Check if this state is terminal (no more transitions possible). + pub fn is_terminal(&self) -> bool { + matches!( + self, + TaskState::Completed | TaskState::Failed | TaskState::Interrupted + ) + } + + /// Check if the task is currently active (running or paused). + pub fn is_active(&self) -> bool { + matches!( + self, + TaskState::Initializing + | TaskState::Starting + | TaskState::Running + | TaskState::Paused + | TaskState::Blocked + ) + } + + /// Check if the task is running. + pub fn is_running(&self) -> bool { + matches!(self, TaskState::Running) + } + + /// Convert to string for protocol messages. + pub fn as_str(&self) -> &'static str { + match self { + TaskState::Initializing => "initializing", + TaskState::Starting => "starting", + TaskState::Running => "running", + TaskState::Paused => "paused", + TaskState::Blocked => "blocked", + TaskState::Completed => "done", + TaskState::Failed => "failed", + TaskState::Interrupted => "interrupted", + } + } + + /// Parse from string. + pub fn from_str(s: &str) -> Option { + match s.to_lowercase().as_str() { + "initializing" => Some(TaskState::Initializing), + "starting" => Some(TaskState::Starting), + "running" => Some(TaskState::Running), + "paused" => Some(TaskState::Paused), + "blocked" => Some(TaskState::Blocked), + "done" | "completed" => Some(TaskState::Completed), + "failed" => Some(TaskState::Failed), + "interrupted" => Some(TaskState::Interrupted), + _ => None, + } + } +} + +impl fmt::Display for TaskState { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.as_str()) + } +} + +impl Default for TaskState { + fn default() -> Self { + TaskState::Initializing + } +} + +#[cfg(test)] +mod tests { + use crate::daemon::*; + + #[test] + fn test_valid_transitions() { + use TaskState::*; + + // Valid transitions + assert!(Initializing.can_transition_to(Starting)); + assert!(Starting.can_transition_to(Running)); + assert!(Running.can_transition_to(Completed)); + assert!(Running.can_transition_to(Paused)); + assert!(Paused.can_transition_to(Running)); + + // Invalid transitions + assert!(!Completed.can_transition_to(Running)); + assert!(!Failed.can_transition_to(Running)); + assert!(!Running.can_transition_to(Initializing)); + } + + #[test] + fn test_terminal_states() { + assert!(TaskState::Completed.is_terminal()); + assert!(TaskState::Failed.is_terminal()); + assert!(TaskState::Interrupted.is_terminal()); + assert!(!TaskState::Running.is_terminal()); + assert!(!TaskState::Paused.is_terminal()); + } + + #[test] + fn test_parse() { + assert_eq!(TaskState::from_str("running"), Some(TaskState::Running)); + assert_eq!(TaskState::from_str("done"), Some(TaskState::Completed)); + assert_eq!(TaskState::from_str("invalid"), None); + } +} -- cgit v1.2.3