Skip to main content

solverforge_config/
solver_config.rs

1use std::path::Path;
2use std::time::Duration;
3
4use serde::{Deserialize, Serialize};
5
6use crate::director::DirectorConfig;
7use crate::error::ConfigError;
8use crate::phase::PhaseConfig;
9use crate::termination::TerminationConfig;
10
11// Main solver configuration.
12#[derive(Debug, Clone, Default, Deserialize, Serialize)]
13#[serde(rename_all = "snake_case")]
14pub struct SolverConfig {
15    // Environment mode affecting reproducibility and assertions.
16    #[serde(default)]
17    pub environment_mode: EnvironmentMode,
18
19    // Random seed for reproducible results.
20    #[serde(default)]
21    pub random_seed: Option<u64>,
22
23    // Number of threads for parallel move evaluation.
24    #[serde(default)]
25    pub move_thread_count: MoveThreadCount,
26
27    // Termination configuration.
28    #[serde(default)]
29    pub termination: Option<TerminationConfig>,
30
31    // Score director configuration.
32    #[serde(default)]
33    pub score_director: Option<DirectorConfig>,
34
35    // Phase configurations.
36    #[serde(default)]
37    pub phases: Vec<PhaseConfig>,
38}
39
40impl SolverConfig {
41    pub fn new() -> Self {
42        Self::default()
43    }
44
45    /// Loads configuration from a TOML file.
46    ///
47    /// # Errors
48    ///
49    /// Returns error if file doesn't exist or contains invalid TOML.
50    pub fn load(path: impl AsRef<Path>) -> Result<Self, ConfigError> {
51        Self::from_toml_file(path)
52    }
53
54    /// Loads configuration from a TOML file.
55    pub fn from_toml_file(path: impl AsRef<Path>) -> Result<Self, ConfigError> {
56        let contents = std::fs::read_to_string(path)?;
57        Self::from_toml_str(&contents)
58    }
59
60    /// Parses configuration from a TOML string.
61    pub fn from_toml_str(s: &str) -> Result<Self, ConfigError> {
62        Ok(toml::from_str(s)?)
63    }
64
65    /// Loads configuration from a YAML file.
66    pub fn from_yaml_file(path: impl AsRef<Path>) -> Result<Self, ConfigError> {
67        let contents = std::fs::read_to_string(path)?;
68        Self::from_yaml_str(&contents)
69    }
70
71    /// Parses configuration from a YAML string.
72    pub fn from_yaml_str(s: &str) -> Result<Self, ConfigError> {
73        Ok(serde_yaml::from_str(s)?)
74    }
75
76    pub fn with_termination_seconds(mut self, seconds: u64) -> Self {
77        self.termination = Some(TerminationConfig {
78            seconds_spent_limit: Some(seconds),
79            ..self.termination.unwrap_or_default()
80        });
81        self
82    }
83
84    pub fn with_random_seed(mut self, seed: u64) -> Self {
85        self.random_seed = Some(seed);
86        self
87    }
88
89    pub fn with_phase(mut self, phase: PhaseConfig) -> Self {
90        self.phases.push(phase);
91        self
92    }
93
94    /// Returns the termination time limit, if configured.
95    ///
96    /// Convenience method that delegates to `termination.time_limit()`.
97    ///
98    /// # Examples
99    ///
100    /// ```
101    /// use solverforge_config::SolverConfig;
102    /// use std::time::Duration;
103    ///
104    /// let config = SolverConfig::from_toml_str(r#"
105    ///     [termination]
106    ///     seconds_spent_limit = 30
107    /// "#).unwrap();
108    ///
109    /// assert_eq!(config.time_limit(), Some(Duration::from_secs(30)));
110    /// ```
111    pub fn time_limit(&self) -> Option<Duration> {
112        self.termination.as_ref().and_then(|t| t.time_limit())
113    }
114}
115
116// Environment mode affecting solver behavior.
117#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Deserialize, Serialize)]
118#[serde(rename_all = "snake_case")]
119pub enum EnvironmentMode {
120    // Non-reproducible mode with minimal overhead.
121    #[default]
122    NonReproducible,
123
124    // Reproducible mode with deterministic behavior.
125    Reproducible,
126
127    // Fast assert mode with basic assertions.
128    FastAssert,
129
130    // Full assert mode with comprehensive assertions.
131    FullAssert,
132}
133
134// Move thread count configuration.
135#[derive(Debug, Clone, Default, PartialEq, Eq, Deserialize, Serialize)]
136#[serde(rename_all = "snake_case")]
137pub enum MoveThreadCount {
138    // Automatically determine thread count.
139    #[default]
140    Auto,
141
142    // No parallel move evaluation.
143    None,
144
145    // Specific number of threads.
146    Count(usize),
147}
148
149// Runtime configuration overrides.
150#[derive(Debug, Clone, Default)]
151pub struct SolverConfigOverride {
152    // Override termination configuration.
153    pub termination: Option<TerminationConfig>,
154}
155
156impl SolverConfigOverride {
157    pub fn with_termination(termination: TerminationConfig) -> Self {
158        SolverConfigOverride {
159            termination: Some(termination),
160        }
161    }
162}