laddu_expr/error.rs
1use thiserror::Error;
2
3/// Result type for parameter construction and lookup operations.
4pub type ParamResult<T> = Result<T, ParamError>;
5/// Result type for expression construction and validation operations.
6pub type ExprResult<T> = Result<T, ExprError>;
7
8/// Errors produced while defining, laying out, or assigning parameters.
9#[derive(Clone, Debug, Error, PartialEq)]
10pub enum ParamError {
11 /// A parameter name was empty.
12 #[error("parameter name cannot be empty")]
13 EmptyName,
14 #[error("duplicate parameter name: {0}")]
15 /// A parameter name was registered more than once.
16 DuplicateName(String),
17 #[error("unknown parameter: {0}")]
18 /// A parameter name was not present in the layout.
19 UnknownName(String),
20 #[error("parameter conflict for {name}: {reason}")]
21 /// Two definitions of the same parameter were incompatible.
22 ParameterConflict {
23 /// Conflicting parameter name.
24 name: String,
25 /// Description of the incompatibility.
26 reason: String,
27 },
28 /// A parameter identifier was outside the layout.
29 #[error("invalid parameter id #{id} for layout of size {len}")]
30 InvalidParamId {
31 /// Invalid identifier index.
32 id: usize,
33 /// Number of parameters in the layout.
34 len: usize,
35 },
36 /// A free-parameter identifier was outside the layout.
37 #[error("invalid free parameter id #{id} for layout with {len} free parameters")]
38 InvalidFreeParamId {
39 /// Invalid free-parameter index.
40 id: usize,
41 /// Number of free parameters in the layout.
42 len: usize,
43 },
44 /// A free-parameter value vector had the wrong length.
45 #[error("expected {expected} free parameters, got {actual}")]
46 FreeLengthMismatch {
47 /// Required number of values.
48 expected: usize,
49 /// Supplied number of values.
50 actual: usize,
51 },
52 /// A parameter's lower bound exceeded its upper bound.
53 #[error("invalid bounds for {name}: min {min} is greater than max {max}")]
54 InvalidBounds {
55 /// Parameter name.
56 name: String,
57 /// Invalid lower bound.
58 min: f64,
59 /// Invalid upper bound.
60 max: f64,
61 },
62 /// A uniform initial range had its endpoints reversed.
63 #[error("invalid uniform initial range for {name}: min {min} is greater than max {max}")]
64 InvalidInitialRange {
65 /// Parameter name.
66 name: String,
67 /// Invalid range minimum.
68 min: f64,
69 /// Invalid range maximum.
70 max: f64,
71 },
72 /// A parameter's initial value fell outside its bounds.
73 #[error("initial value {value} for {name} is outside bounds")]
74 InitialOutOfBounds {
75 /// Parameter name.
76 name: String,
77 /// Invalid initial value.
78 value: f64,
79 },
80 /// A parameter's initial range extended outside its bounds.
81 #[error("initial range [{min}, {max}] for {name} is outside parameter bounds")]
82 InitialRangeOutOfBounds {
83 /// Parameter name.
84 name: String,
85 /// Initial range minimum.
86 min: f64,
87 /// Initial range maximum.
88 max: f64,
89 },
90 /// A fixed parameter value fell outside its bounds.
91 #[error("fixed value {value} for {name} is outside bounds")]
92 FixedValueOutOfBounds {
93 /// Parameter name.
94 name: String,
95 /// Invalid fixed value.
96 value: f64,
97 },
98 /// An assigned parameter value fell outside its bounds.
99 #[error("value {value} for {name} is outside bounds")]
100 ValueOutOfBounds {
101 /// Parameter name.
102 name: String,
103 /// Invalid assigned value.
104 value: f64,
105 },
106 /// A periodic parameter did not have finite, ordered bounds.
107 #[error("periodic parameter {name} requires finite two-sided bounds with min < max")]
108 PeriodicRequiresFiniteBounds {
109 /// Parameter name.
110 name: String,
111 },
112 /// A parameter scale was not finite and positive.
113 #[error("invalid scale for {name}: expected a finite positive value, got {scale}")]
114 InvalidScale {
115 /// Parameter name.
116 name: String,
117 /// Invalid scale.
118 scale: f64,
119 },
120 /// A periodic value was outside its canonical half-open domain.
121 #[error(
122 "value {value} for periodic parameter {name} is outside canonical domain [{min}, {max})"
123 )]
124 ValueOutsidePeriodicDomain {
125 /// Parameter name.
126 name: String,
127 /// Invalid value.
128 value: f64,
129 /// Inclusive domain minimum.
130 min: f64,
131 /// Exclusive domain maximum.
132 max: f64,
133 },
134}
135
136/// Structural validation errors for serialized expression graphs.
137#[derive(Clone, Debug, Error, PartialEq, Eq)]
138pub enum ExprGraphError {
139 /// The node and metadata arrays had different lengths.
140 #[error("graph metadata length {metadata_len} does not match node length {node_len}")]
141 MetadataLength {
142 /// Number of graph nodes.
143 node_len: usize,
144 /// Number of metadata entries.
145 metadata_len: usize,
146 },
147 /// The root identifier was outside the node array.
148 #[error("graph root node #{root} is out of bounds for graph with {node_len} nodes")]
149 InvalidRoot {
150 /// Invalid root index.
151 root: usize,
152 /// Number of graph nodes.
153 node_len: usize,
154 },
155 /// A node referenced a child outside the node array.
156 #[error("graph node #{node} references missing child #{child}")]
157 InvalidChild {
158 /// Parent node index.
159 node: usize,
160 /// Invalid child index.
161 child: usize,
162 },
163 /// A node referenced a child stored after its parent.
164 #[error(
165 "graph node #{node} references child #{child}, but children must appear before parents"
166 )]
167 InvalidChildOrder {
168 /// Parent node index.
169 node: usize,
170 /// Out-of-order child index.
171 child: usize,
172 },
173 /// The graph contained no nodes.
174 #[error("graph is empty")]
175 Empty,
176}
177
178/// Describes an operation applied to an expression with an incompatible shape.
179#[derive(Clone, Debug, Error, PartialEq, Eq)]
180#[error("invalid expression shape for {operation}: {message}")]
181pub struct ExprShapeError {
182 operation: &'static str,
183 message: String,
184}
185
186impl ExprShapeError {
187 pub(crate) fn new(operation: &'static str, message: impl Into<String>) -> Self {
188 Self {
189 operation,
190 message: message.into(),
191 }
192 }
193}
194
195/// Errors produced while constructing or rebuilding expressions.
196#[derive(Clone, Debug, Error, PartialEq)]
197pub enum ExprError {
198 /// A parameter operation failed.
199 #[error(transparent)]
200 Params(#[from] ParamError),
201 /// A serialized graph was structurally invalid.
202 #[error(transparent)]
203 Graph(#[from] ExprGraphError),
204 /// An operation received incompatible expression shapes.
205 #[error(transparent)]
206 Shape(#[from] ExprShapeError),
207}