swarm-engine-core 0.1.6

Core types and orchestration for SwarmEngine
Documentation
//! Termination configuration
//!
//! Configuration for termination behavior.

use serde::{Deserialize, Serialize};

/// Termination configuration
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TerminationConfig {
    /// Maximum ticks before timeout (0 = no limit)
    pub max_ticks: u64,

    /// Strategy for multi-worker termination
    pub multi_worker_strategy: MultiWorkerStrategy,

    /// Behavior when exploration is exhausted
    pub on_exhausted: ExhaustedBehavior,

    /// Maximum consecutive errors before failure
    pub max_consecutive_errors: Option<u64>,

    /// Whether to allow graceful shutdown period
    pub graceful_shutdown_ticks: u64,
}

impl Default for TerminationConfig {
    fn default() -> Self {
        Self {
            max_ticks: 1000,
            multi_worker_strategy: MultiWorkerStrategy::FirstSuccess,
            on_exhausted: ExhaustedBehavior::Fail,
            max_consecutive_errors: None,
            graceful_shutdown_ticks: 0,
        }
    }
}

/// Strategy for handling multiple workers
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
#[serde(rename_all = "snake_case")]
pub enum MultiWorkerStrategy {
    /// Terminate when first worker succeeds
    #[default]
    FirstSuccess,
    /// Terminate when all workers complete (success if any succeeded)
    AllComplete,
    /// Terminate when all workers succeed
    AllSuccess,
    /// Custom logic (check conditions)
    Conditions,
}

/// Behavior when exploration is exhausted
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
#[serde(rename_all = "snake_case")]
pub enum ExhaustedBehavior {
    /// Treat as failure
    #[default]
    Fail,
    /// Treat as success (exploration naturally completed)
    Success,
    /// Check conditions to determine outcome
    CheckConditions,
}

impl TerminationConfig {
    /// Create config with max_ticks
    pub fn with_max_ticks(max_ticks: u64) -> Self {
        Self {
            max_ticks,
            ..Default::default()
        }
    }

    /// Set multi-worker strategy
    pub fn multi_worker_strategy(mut self, strategy: MultiWorkerStrategy) -> Self {
        self.multi_worker_strategy = strategy;
        self
    }

    /// Set exhausted behavior
    pub fn on_exhausted(mut self, behavior: ExhaustedBehavior) -> Self {
        self.on_exhausted = behavior;
        self
    }

    /// Set max consecutive errors
    pub fn max_consecutive_errors(mut self, max: u64) -> Self {
        self.max_consecutive_errors = Some(max);
        self
    }
}

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

    #[test]
    fn test_default_config() {
        let config = TerminationConfig::default();
        assert_eq!(config.max_ticks, 1000);
        assert_eq!(
            config.multi_worker_strategy,
            MultiWorkerStrategy::FirstSuccess
        );
        assert_eq!(config.on_exhausted, ExhaustedBehavior::Fail);
    }

    #[test]
    fn test_builder_pattern() {
        let config = TerminationConfig::with_max_ticks(500)
            .multi_worker_strategy(MultiWorkerStrategy::AllSuccess)
            .on_exhausted(ExhaustedBehavior::Success);

        assert_eq!(config.max_ticks, 500);
        assert_eq!(
            config.multi_worker_strategy,
            MultiWorkerStrategy::AllSuccess
        );
        assert_eq!(config.on_exhausted, ExhaustedBehavior::Success);
    }
}