Skip to main content

molrs_compute/
error.rs

1use std::fmt;
2
3use molrs::MolRsError;
4
5/// Node identifier (formerly from `crate::graph`, now defined locally
6/// since the graph module is decoupled from the crate).
7#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
8pub struct NodeId(pub u32);
9
10/// Error type for compute operations.
11#[derive(Debug)]
12pub enum ComputeError {
13    /// Required block not found in Frame.
14    MissingBlock { name: &'static str },
15
16    /// Required column not found in a block.
17    MissingColumn {
18        block: &'static str,
19        col: &'static str,
20    },
21
22    /// Frame has no SimBox but the compute requires one.
23    MissingSimBox,
24
25    /// Array dimensions do not match expectations.
26    DimensionMismatch {
27        expected: usize,
28        got: usize,
29        what: &'static str,
30    },
31
32    /// A composite value has the wrong shape (e.g. ragged matrix).
33    BadShape { expected: String, got: String },
34
35    /// Non-finite value (NaN / ±Inf) at the given flat index of the named field.
36    NonFinite { where_: &'static str, index: usize },
37
38    /// Scalar input out of its valid range.
39    OutOfRange { field: &'static str, value: String },
40
41    /// `frames` slice is empty but the compute needs at least one frame.
42    EmptyInput,
43
44    /// Graph DAG contains a cycle involving these nodes.
45    CyclicDependency { nodes: Vec<NodeId> },
46
47    /// `Inputs` did not bind a value for this input slot.
48    MissingInput { slot: NodeId },
49
50    /// Value stored at a slot has a different type than the accessor expects.
51    TypeMismatch {
52        slot: NodeId,
53        expected: &'static str,
54        got: &'static str,
55    },
56
57    /// A compute node failed; `source` carries the original error, `node_id`
58    /// identifies which node in the Graph raised it.
59    Node {
60        node_id: NodeId,
61        source: Box<ComputeError>,
62    },
63
64    /// Forwarded from molrs-core.
65    MolRs(MolRsError),
66}
67
68impl fmt::Display for ComputeError {
69    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
70        match self {
71            Self::MissingBlock { name } => write!(f, "missing block '{name}' in Frame"),
72            Self::MissingColumn { block, col } => {
73                write!(f, "missing column '{col}' in block '{block}'")
74            }
75            Self::MissingSimBox => write!(f, "Frame has no SimBox"),
76            Self::DimensionMismatch {
77                expected,
78                got,
79                what,
80            } => write!(
81                f,
82                "{what} dimension mismatch: expected {expected}, got {got}"
83            ),
84            Self::BadShape { expected, got } => {
85                write!(f, "bad shape: expected {expected}, got {got}")
86            }
87            Self::NonFinite { where_, index } => {
88                write!(f, "non-finite value in {where_} at index {index}")
89            }
90            Self::OutOfRange { field, value } => {
91                write!(f, "{field} out of range: {value}")
92            }
93            Self::EmptyInput => write!(f, "empty frames slice"),
94            Self::CyclicDependency { nodes } => {
95                write!(f, "cyclic dependency among nodes {nodes:?}")
96            }
97            Self::MissingInput { slot } => {
98                write!(f, "input slot {slot:?} not bound in Inputs")
99            }
100            Self::TypeMismatch {
101                slot,
102                expected,
103                got,
104            } => write!(
105                f,
106                "type mismatch for slot {slot:?}: expected {expected}, got {got}"
107            ),
108            Self::Node { node_id, source } => {
109                write!(f, "node {node_id:?} failed: {source}")
110            }
111            Self::MolRs(e) => write!(f, "{e}"),
112        }
113    }
114}
115
116impl std::error::Error for ComputeError {
117    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
118        match self {
119            Self::MolRs(e) => Some(e),
120            Self::Node { source, .. } => Some(source.as_ref()),
121            _ => None,
122        }
123    }
124}
125
126impl From<MolRsError> for ComputeError {
127    fn from(err: MolRsError) -> Self {
128        Self::MolRs(err)
129    }
130}