Skip to main content

solverforge_solver/
runtime_build_error.rs

1//! Fallible boundaries for configured runtime declaration and preparation.
2//!
3//! The configured runner translates its private compiler and executor errors
4//! into this public, non-graph error surface. Host bindings and generated
5//! macro code can therefore propagate an actionable failure without naming or
6//! constructing a compiled runtime graph.
7
8use std::fmt;
9
10/// Error returned while a configured runtime is being declared, compiled, or
11/// prepared for one solve.
12#[derive(Clone, Debug, PartialEq, Eq)]
13pub enum RuntimeBuildError {
14    /// The descriptor-backed runtime declaration could not be formed.
15    Declaration {
16        /// Actionable explanation of the invalid declaration.
17        message: String,
18    },
19    /// The private runtime graph compiler rejected the declaration.
20    Compilation {
21        /// Structural configuration path that failed validation.
22        path: String,
23        /// Actionable explanation of the compiler rejection.
24        message: String,
25    },
26    /// One structurally valid graph could not be prepared for execution.
27    Preparation {
28        /// Configured phase index being prepared.
29        phase_index: usize,
30        /// Actionable explanation of the preparation failure.
31        message: String,
32    },
33    /// A reached runtime phase could not bind or execute its declared work.
34    Execution {
35        /// Configured phase index that reached the failure boundary.
36        phase_index: usize,
37        /// Actionable explanation of the execution failure.
38        message: String,
39    },
40}
41
42impl RuntimeBuildError {
43    /// Creates a declaration error from descriptor/model resolution.
44    pub fn declaration(message: impl Into<String>) -> Self {
45        Self::Declaration {
46            message: message.into(),
47        }
48    }
49}
50
51impl fmt::Display for RuntimeBuildError {
52    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
53        match self {
54            Self::Declaration { message } => {
55                write!(formatter, "runtime declaration failed: {message}")
56            }
57            Self::Compilation { path, message } => {
58                write!(formatter, "runtime compilation failed at {path}: {message}")
59            }
60            Self::Preparation {
61                phase_index,
62                message,
63            } => {
64                write!(
65                    formatter,
66                    "runtime preparation failed at phase {phase_index}: {message}"
67                )
68            }
69            Self::Execution {
70                phase_index,
71                message,
72            } => {
73                write!(
74                    formatter,
75                    "runtime execution failed at phase {phase_index}: {message}"
76                )
77            }
78        }
79    }
80}
81
82impl std::error::Error for RuntimeBuildError {}
83
84/// Result returned by the one configured-runtime declaration/preparation path.
85pub type RuntimeBuildResult<T> = Result<T, RuntimeBuildError>;
86
87#[cfg(test)]
88mod tests {
89    use super::RuntimeBuildError;
90
91    #[test]
92    fn display_keeps_the_runtime_build_boundary_and_structural_location() {
93        assert_eq!(
94            RuntimeBuildError::declaration("unknown variable").to_string(),
95            "runtime declaration failed: unknown variable"
96        );
97        assert_eq!(
98            RuntimeBuildError::Compilation {
99                path: "phases[1]".to_string(),
100                message: "missing route hooks".to_string(),
101            }
102            .to_string(),
103            "runtime compilation failed at phases[1]: missing route hooks"
104        );
105        assert_eq!(
106            RuntimeBuildError::Preparation {
107                phase_index: 2,
108                message: "source key collision".to_string(),
109            }
110            .to_string(),
111            "runtime preparation failed at phase 2: source key collision"
112        );
113        assert_eq!(
114            RuntimeBuildError::Execution {
115                phase_index: 3,
116                message: "source callback failed".to_string(),
117            }
118            .to_string(),
119            "runtime execution failed at phase 3: source callback failed"
120        );
121    }
122}