causal_hub/types/
error.rs1use std::{panic::Location, sync::Arc};
2
3use thiserror::Error;
4
5#[derive(Error, Debug, Clone)]
7pub enum ErrorKind {
8 #[error(transparent)]
10 Io(Arc<std::io::Error>),
11 #[error(transparent)]
13 Csv(Arc<csv::Error>),
14 #[error(transparent)]
16 Json(Arc<serde_json::Error>),
17 #[error(transparent)]
19 Utf8(#[from] std::string::FromUtf8Error),
20 #[error(transparent)]
22 ParseFloat(#[from] std::num::ParseFloatError),
23 #[error(transparent)]
25 NdarrayShape(#[from] ndarray::ShapeError),
26 #[error(transparent)]
28 NdarrayMinMax(#[from] ndarray_stats::errors::MinMaxError),
29 #[error(transparent)]
31 RandDistrUniform(#[from] rand_distr::uniform::Error),
32 #[error("Linear Algebra error: {0}")]
34 Linalg(String),
35 #[error("Probability error: {0}")]
37 Probability(String),
38 #[error("Parsing error: {0}")]
40 Parsing(String),
41 #[error("Missing data error: {0}")]
43 MissingData(String),
44 #[error("Statistics error: {0}")]
46 Stats(String),
47 #[error("Random distribution error: {0}")]
49 RandDistr(String),
50 #[error("Shape error: {0}")]
52 Shape(String),
53 #[error("Unreachable error: {0}")]
55 Unreachable(String),
56 #[error("Lock poisoning error: {0}")]
58 Poison(String),
59 #[error("Index `{0}` is out of bounds")]
61 IndexOutOfBounds(usize),
62 #[error("Labels must be unique.")]
64 NonUniqueLabels,
65 #[error("Set {0} must not be empty")]
67 EmptySet(String),
68 #[error("Sets {0} and {1} must be disjoint")]
70 SetsNotDisjoint(String, String),
71 #[error("Set {0} must be a subset of set {1}")]
73 SubsetMismatch(String, String),
74 #[error("Graph must be a DAG")]
76 NotADag,
77 #[error("Invalid parameter {0}: {1}")]
79 InvalidParameter(String, String),
80 #[error("Prior knowledge conflict: {0}")]
82 PriorKnowledgeConflict(String),
83 #[error("Labels mismatch: {0} != {1}")]
85 LabelMismatch(String, String),
86 #[error("Missing sufficient statistics")]
88 MissingSufficientStatistics,
89 #[error("Missing log-likelihood")]
91 MissingLogLikelihood,
92 #[error("CSV file must have headers")]
94 MissingHeader,
95 #[error("Incompatible shape: {0} != {1}")]
97 IncompatibleShape(String, String),
98 #[error("State {0} not found")]
100 MissingState(String),
101 #[error("Label {0} not found")]
103 MissingLabel(String),
104 #[error("Value is NaN")]
106 NanValue,
107 #[error("Missing value at line {0}, column {1}")]
109 MissingValue(usize, usize),
110 #[error("Object construction failed: {0}")]
112 ConstructionError(String),
113 #[error(transparent)]
115 Other(Arc<Box<dyn std::error::Error + Send + Sync>>),
116}
117
118#[derive(Debug, Clone)]
120pub struct Error {
121 pub kind: ErrorKind,
123 pub location: &'static Location<'static>,
125}
126
127impl std::fmt::Display for Error {
128 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
129 write!(f, "{} at {}", self.kind, self.location)
130 }
131}
132
133impl std::error::Error for Error {
134 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
135 self.kind.source()
136 }
137}
138
139impl From<ErrorKind> for Error {
140 #[track_caller]
141 fn from(kind: ErrorKind) -> Self {
142 Self {
143 kind,
144 location: Location::caller(),
145 }
146 }
147}
148
149impl From<std::io::Error> for Error {
150 #[track_caller]
151 fn from(err: std::io::Error) -> Self {
152 ErrorKind::Io(Arc::new(err)).into()
153 }
154}
155
156impl From<csv::Error> for Error {
157 #[track_caller]
158 fn from(err: csv::Error) -> Self {
159 ErrorKind::Csv(Arc::new(err)).into()
160 }
161}
162
163impl From<serde_json::Error> for Error {
164 #[track_caller]
165 fn from(err: serde_json::Error) -> Self {
166 ErrorKind::Json(Arc::new(err)).into()
167 }
168}
169
170impl From<Box<dyn std::error::Error + Send + Sync>> for Error {
171 #[track_caller]
172 fn from(err: Box<dyn std::error::Error + Send + Sync>) -> Self {
173 ErrorKind::Other(Arc::new(err)).into()
174 }
175}
176
177impl From<std::string::FromUtf8Error> for Error {
178 #[track_caller]
179 fn from(err: std::string::FromUtf8Error) -> Self {
180 ErrorKind::Utf8(err).into()
181 }
182}
183
184impl From<std::num::ParseFloatError> for Error {
185 #[track_caller]
186 fn from(err: std::num::ParseFloatError) -> Self {
187 ErrorKind::ParseFloat(err).into()
188 }
189}
190
191impl From<ndarray::ShapeError> for Error {
192 #[track_caller]
193 fn from(err: ndarray::ShapeError) -> Self {
194 ErrorKind::NdarrayShape(err).into()
195 }
196}
197
198impl From<ndarray_stats::errors::MinMaxError> for Error {
199 #[track_caller]
200 fn from(err: ndarray_stats::errors::MinMaxError) -> Self {
201 ErrorKind::NdarrayMinMax(err).into()
202 }
203}
204
205impl From<rand_distr::uniform::Error> for Error {
206 #[track_caller]
207 fn from(err: rand_distr::uniform::Error) -> Self {
208 ErrorKind::RandDistrUniform(err).into()
209 }
210}
211
212pub type Result<T> = std::result::Result<T, Error>;
214
215impl serde::Serialize for Error {
216 fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
217 where
218 S: serde::Serializer,
219 {
220 serializer.serialize_str(&self.to_string())
221 }
222}
223
224#[track_caller]
226pub fn err<T>(kind: ErrorKind) -> Result<T> {
227 Err(Error::from(kind))
228}
229
230impl Error {
232 #[allow(non_snake_case)]
234 #[track_caller]
235 pub fn Linalg(stats: &str) -> Self {
236 ErrorKind::Linalg(stats.to_string()).into()
237 }
238
239 #[allow(non_snake_case)]
241 #[track_caller]
242 pub fn Probability(stats: &str) -> Self {
243 ErrorKind::Probability(stats.to_string()).into()
244 }
245
246 #[allow(non_snake_case)]
248 #[track_caller]
249 pub fn Parsing(stats: &str) -> Self {
250 ErrorKind::Parsing(stats.to_string()).into()
251 }
252
253 #[allow(non_snake_case)]
255 #[track_caller]
256 pub fn MissingData(stats: &str) -> Self {
257 ErrorKind::MissingData(stats.to_string()).into()
258 }
259
260 #[allow(non_snake_case)]
262 #[track_caller]
263 pub fn Stats(stats: &str) -> Self {
264 ErrorKind::Stats(stats.to_string()).into()
265 }
266
267 #[allow(non_snake_case)]
269 #[track_caller]
270 pub fn RandDistr(stats: &str) -> Self {
271 ErrorKind::RandDistr(stats.to_string()).into()
272 }
273
274 #[allow(non_snake_case)]
276 #[track_caller]
277 pub fn Shape(stats: &str) -> Self {
278 ErrorKind::Shape(stats.to_string()).into()
279 }
280
281 #[allow(non_snake_case)]
283 #[track_caller]
284 pub fn Unreachable(stats: &str) -> Self {
285 ErrorKind::Unreachable(stats.to_string()).into()
286 }
287
288 #[allow(non_snake_case)]
290 #[track_caller]
291 pub fn Poison(stats: &str) -> Self {
292 ErrorKind::Poison(stats.to_string()).into()
293 }
294
295 #[allow(non_snake_case)]
297 #[track_caller]
298 pub fn IndexOutOfBounds(u: usize) -> Self {
299 ErrorKind::IndexOutOfBounds(u).into()
300 }
301
302 #[allow(non_snake_case)]
304 #[track_caller]
305 pub fn NonUniqueLabels() -> Self {
306 ErrorKind::NonUniqueLabels.into()
307 }
308
309 #[allow(non_snake_case)]
311 #[track_caller]
312 pub fn EmptySet(stats: &str) -> Self {
313 ErrorKind::EmptySet(stats.to_string()).into()
314 }
315
316 #[allow(non_snake_case)]
318 #[track_caller]
319 pub fn SetsNotDisjoint(s1: &str, s2: &str) -> Self {
320 ErrorKind::SetsNotDisjoint(s1.to_string(), s2.to_string()).into()
321 }
322
323 #[allow(non_snake_case)]
325 #[track_caller]
326 pub fn SubsetMismatch(s1: &str, s2: &str) -> Self {
327 ErrorKind::SubsetMismatch(s1.to_string(), s2.to_string()).into()
328 }
329
330 #[allow(non_snake_case)]
332 #[track_caller]
333 pub fn NotADag() -> Self {
334 ErrorKind::NotADag.into()
335 }
336
337 #[allow(non_snake_case)]
339 #[track_caller]
340 pub fn InvalidParameter(s1: &str, s2: &str) -> Self {
341 ErrorKind::InvalidParameter(s1.to_string(), s2.to_string()).into()
342 }
343
344 #[allow(non_snake_case)]
346 #[track_caller]
347 pub fn PriorKnowledgeConflict(stats: &str) -> Self {
348 ErrorKind::PriorKnowledgeConflict(stats.to_string()).into()
349 }
350
351 #[allow(non_snake_case)]
353 #[track_caller]
354 pub fn LabelMismatch(s1: &str, s2: &str) -> Self {
355 ErrorKind::LabelMismatch(s1.to_string(), s2.to_string()).into()
356 }
357
358 #[allow(non_snake_case)]
360 #[track_caller]
361 pub fn MissingSufficientStatistics() -> Self {
362 ErrorKind::MissingSufficientStatistics.into()
363 }
364
365 #[allow(non_snake_case)]
367 #[track_caller]
368 pub fn MissingLogLikelihood() -> Self {
369 ErrorKind::MissingLogLikelihood.into()
370 }
371
372 #[allow(non_snake_case)]
374 #[track_caller]
375 pub fn MissingHeader() -> Self {
376 ErrorKind::MissingHeader.into()
377 }
378
379 #[allow(non_snake_case)]
381 #[track_caller]
382 pub fn IncompatibleShape(s1: &str, s2: &str) -> Self {
383 ErrorKind::IncompatibleShape(s1.to_string(), s2.to_string()).into()
384 }
385
386 #[allow(non_snake_case)]
388 #[track_caller]
389 pub fn MissingState(stats: &str) -> Self {
390 ErrorKind::MissingState(stats.to_string()).into()
391 }
392
393 #[allow(non_snake_case)]
395 #[track_caller]
396 pub fn MissingLabel(stats: &str) -> Self {
397 ErrorKind::MissingLabel(stats.to_string()).into()
398 }
399
400 #[allow(non_snake_case)]
402 #[track_caller]
403 pub fn NanValue() -> Self {
404 ErrorKind::NanValue.into()
405 }
406
407 #[allow(non_snake_case)]
409 #[track_caller]
410 pub fn MissingValue(u1: usize, u2: usize) -> Self {
411 ErrorKind::MissingValue(u1, u2).into()
412 }
413
414 #[allow(non_snake_case)]
416 #[track_caller]
417 pub fn ConstructionError(stats: &str) -> Self {
418 ErrorKind::ConstructionError(stats.to_string()).into()
419 }
420}
421
422impl Error {
424 #[allow(non_snake_case)]
426 #[track_caller]
427 pub fn Io(err: Arc<std::io::Error>) -> Self {
428 ErrorKind::Io(err).into()
429 }
430
431 #[allow(non_snake_case)]
433 #[track_caller]
434 pub fn Csv(err: Arc<csv::Error>) -> Self {
435 ErrorKind::Csv(err).into()
436 }
437
438 #[allow(non_snake_case)]
440 #[track_caller]
441 pub fn Json(err: Arc<serde_json::Error>) -> Self {
442 ErrorKind::Json(err).into()
443 }
444
445 #[allow(non_snake_case)]
447 #[track_caller]
448 pub fn Utf8(err: std::string::FromUtf8Error) -> Self {
449 ErrorKind::Utf8(err).into()
450 }
451
452 #[allow(non_snake_case)]
454 #[track_caller]
455 pub fn ParseFloat(err: std::num::ParseFloatError) -> Self {
456 ErrorKind::ParseFloat(err).into()
457 }
458
459 #[allow(non_snake_case)]
461 #[track_caller]
462 pub fn NdarrayShape(err: ndarray::ShapeError) -> Self {
463 ErrorKind::NdarrayShape(err).into()
464 }
465
466 #[allow(non_snake_case)]
468 #[track_caller]
469 pub fn NdarrayMinMax(err: ndarray_stats::errors::MinMaxError) -> Self {
470 ErrorKind::NdarrayMinMax(err).into()
471 }
472
473 #[allow(non_snake_case)]
475 #[track_caller]
476 pub fn RandDistrUniform(err: rand_distr::uniform::Error) -> Self {
477 ErrorKind::RandDistrUniform(err).into()
478 }
479
480 #[allow(non_snake_case)]
482 #[track_caller]
483 pub fn Other(err: Arc<Box<dyn std::error::Error + Send + Sync>>) -> Self {
484 ErrorKind::Other(err).into()
485 }
486}