cellular_raza_core/backend/cpu_os_threads/errors.rs
1use crate::storage::StorageError;
2use cellular_raza_concepts::*;
3use core::any::type_name;
4use core::fmt::{Debug, Display};
5
6use std::error::Error; // TODO in the future use core::error::Error (unstable right now)
7
8use crossbeam_channel::{RecvError, SendError};
9
10macro_rules! impl_error_variant {
11 ($name: ident, $($err_var: ident),+) => {
12 // Implement Display for ErrorVariant
13 impl Display for $name {
14 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
15 match self {
16 $(
17 $name::$err_var(message) => write!(f, "{}", message),
18 )+
19 }
20 }
21 }
22 }
23}
24
25macro_rules! impl_from_error {
26 ($name: ident, $(($err_var: ident, $err_type: ty)),+) => {
27 $(
28 // Implement conversion from error to errorvariant
29 impl From<$err_type> for $name {
30 fn from(err: $err_type) -> Self {
31 $name::$err_var(err)
32 }
33 }
34 )+
35 }
36}
37
38/// Covers all errors that can occur in this Simulation
39///
40/// This main error type should be derivable from errors arising during the simulation process.
41/// It is required for custom error types `MyCustomError` of the engine to implement the
42/// `From<MyCustomError> for SimulationError`.
43///
44/// Errors are separated by their ability to be recovered, ignored or handled otherwise.
45/// Since this crate aims to provide an adaptive solving approach, it is desired to have a fallback
46/// mechanism which can be called for errors which may arise due to precision problems.
47#[derive(Debug)]
48pub enum SimulationError {
49 // Very likely to be user errors
50 /// Occurs during calculations of any mathematical update steps such as
51 /// [Interaction](cellular_raza_concepts::Interaction) between cells.
52 CalcError(CalcError),
53 /// Related to time-stepping events. See [crate::time].
54 TimeError(TimeError),
55 /// Error-type specifically related to the
56 /// [Controller](cellular_raza_concepts::domain_old::Controller) trait.
57 ControllerError(ControllerError),
58 /// An error specific to cell-division events by the
59 ///
60 /// [Cycle](cellular_raza_concepts::Cycle) trait.
61 DivisionError(DivisionError),
62 /// Related to the [PhasedDeath](cellular_raza_concepts::CycleEvent::PhasedDeath) event.
63 /// This error can only occur during the
64 /// [update_conditional_phased_death](cellular_raza_concepts::Cycle::update_conditional_phased_death)
65 /// method.
66 DeathError(DeathError),
67 /// Enforcing boundary conditions on cells can exhibhit this boundary error.
68 BoundaryError(BoundaryError),
69 /// Plotting results. See also [cellular_raza_concepts::PlotSelf] and [cellular_raza_concepts::CreatePlottingRoot].
70 DrawingError(DrawingError),
71 /// Mostly caused by trying to find a voxel by its index.
72 /// This error can also occur when applying too large simulation-steps.
73 IndexError(IndexError),
74
75 // Less likely but possible to be user errors
76 /// Sending information between threads fails
77 SendError(String),
78 /// Receiving information from another thread fails
79 ReceiveError(RecvError),
80 /// Storing results fails
81 StorageError(StorageError),
82
83 // Highly unlikely to be user errors
84 /// When writing to output files or reading from them.
85 /// See [std::io::Error]
86 IoError(std::io::Error),
87 /// Occurs when requested data could not be returned
88 RequestError(RequestError),
89 /// Errors related to [rand] and its functionalities
90 RngError(RngError),
91
92 // Highly unlikely to be user errors
93 /// Errors surrounding construction of [rayon::ThreadPool].
94 ThreadingError(rayon::ThreadPoolBuildError),
95}
96
97impl_from_error! {SimulationError,
98 (ReceiveError, RecvError),
99 (CalcError, CalcError),
100 (ControllerError, ControllerError),
101 (RequestError, RequestError),
102 (TimeError, TimeError),
103 (DivisionError, DivisionError),
104 (DeathError, DeathError),
105 (BoundaryError, BoundaryError),
106 (IndexError, IndexError),
107 (IoError, std::io::Error),
108 (DrawingError, DrawingError),
109 (RngError, RngError),
110 (StorageError, StorageError),
111 (ThreadingError, rayon::ThreadPoolBuildError)
112}
113
114impl_error_variant! {SimulationError,
115 SendError,
116 ReceiveError,
117 RequestError,
118 CalcError,
119 ControllerError,
120 TimeError,
121 DivisionError,
122 DeathError,
123 BoundaryError,
124 IndexError,
125 IoError,
126 DrawingError,
127 RngError,
128 StorageError,
129 ThreadingError
130}
131
132// Implement the general error property
133impl std::error::Error for SimulationError {}
134
135// Implement conversion from Sending error manually
136impl<T> From<SendError<T>> for SimulationError {
137 fn from(_err: SendError<T>) -> Self {
138 SimulationError::SendError(format!(
139 "Error receiving object of type {}",
140 type_name::<SendError<T>>()
141 ))
142 }
143}
144
145impl<E> From<plotters::drawing::DrawingAreaErrorKind<E>> for SimulationError
146where
147 E: Error + Send + Sync,
148{
149 fn from(drawing_error: plotters::drawing::DrawingAreaErrorKind<E>) -> SimulationError {
150 SimulationError::DrawingError(DrawingError::from(drawing_error))
151 }
152}