Skip to main content

sim_lib_interference_solve/
error.rs

1//! Stable diagnostics for reference-solver admission and execution.
2
3use std::fmt;
4
5use sim_lib_interference_core::InterferenceError;
6
7/// A reference solve failed without returning a partial field.
8#[derive(Clone, Debug, PartialEq)]
9pub enum ReferenceSolveError {
10    /// Sampling, work, or another request-wide preflight check failed.
11    Request {
12        /// Exact core diagnostic that refused the request.
13        cause: Box<InterferenceError>,
14    },
15    /// A sampling cell could not be represented by the checked plane.
16    CellGeometry {
17        /// Zero-based row.
18        row: usize,
19        /// Zero-based column.
20        column: usize,
21        /// Exact geometry diagnostic.
22        cause: Box<InterferenceError>,
23    },
24    /// One canonical source could not be evaluated at one sampling cell.
25    SourceAtCell {
26        /// Stable source identity.
27        source_id: String,
28        /// Zero-based row.
29        row: usize,
30        /// Zero-based column.
31        column: usize,
32        /// Exact propagation diagnostic.
33        cause: Box<InterferenceError>,
34    },
35    /// Compensated component accumulation became non-finite.
36    NonFiniteAccumulation {
37        /// Stable source identity after whose contribution the failure arose.
38        source_id: String,
39        /// Zero-based row.
40        row: usize,
41        /// Zero-based column.
42        column: usize,
43        /// Component plane (`real` or `imaginary`).
44        component: &'static str,
45        /// Rejected accumulated value.
46        value: f64,
47    },
48    /// Host storage could not be reserved for a complete component plane.
49    AllocationFailed {
50        /// Component plane whose reservation failed.
51        component: &'static str,
52        /// Requested cell count.
53        cells: usize,
54    },
55}
56
57impl From<InterferenceError> for ReferenceSolveError {
58    fn from(cause: InterferenceError) -> Self {
59        Self::Request {
60            cause: Box::new(cause),
61        }
62    }
63}
64
65impl fmt::Display for ReferenceSolveError {
66    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
67        match self {
68            Self::Request { cause } => {
69                write!(formatter, "reference solve request refused: {cause}")
70            }
71            Self::CellGeometry { row, column, cause } => write!(
72                formatter,
73                "sampling cell ({row}, {column}) has invalid geometry: {cause}"
74            ),
75            Self::SourceAtCell {
76                source_id,
77                row,
78                column,
79                cause,
80            } => write!(
81                formatter,
82                "source `{source_id}` failed at sampling cell ({row}, {column}): {cause}"
83            ),
84            Self::NonFiniteAccumulation {
85                source_id,
86                row,
87                column,
88                component,
89                value,
90            } => write!(
91                formatter,
92                "{component} accumulation became non-finite after source \
93                 `{source_id}` at sampling cell ({row}, {column}): {value:?}"
94            ),
95            Self::AllocationFailed { component, cells } => write!(
96                formatter,
97                "could not reserve {cells} f64 cells for the {component} component plane"
98            ),
99        }
100    }
101}
102
103impl std::error::Error for ReferenceSolveError {
104    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
105        match self {
106            Self::Request { cause }
107            | Self::CellGeometry { cause, .. }
108            | Self::SourceAtCell { cause, .. } => Some(cause.as_ref()),
109            Self::NonFiniteAccumulation { .. } | Self::AllocationFailed { .. } => None,
110        }
111    }
112}