cellular_raza_concepts/
errors.rs

1use core::fmt::Display;
2use std::error::Error;
3
4macro_rules! define_errors {
5    ($(($err_name: ident, $err_descr: expr)),+) => {
6        $(
7            #[doc = $err_descr]
8            #[derive(Debug,Clone)]
9            pub struct $err_name(
10                #[doc = "Error message associated with "]
11                #[doc = stringify!($err_name)]
12                #[doc = " error type."]
13                pub String,
14            );
15
16            impl Display for $err_name {
17                fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
18                    write!(f, "{}", self.0)
19                }
20            }
21
22            impl Error for $err_name {}
23        )+
24    }
25}
26
27/// Error during decomposition of a SimulationDomain into multiple subdomains
28#[derive(Clone, Debug)]
29pub enum DecomposeError {
30    /// Generic error encountered during domain-decomposition
31    Generic(String),
32    /// [BoundaryError] which is encountered during domain-decomposition
33    BoundaryError(BoundaryError),
34    /// [IndexError] encountered during domain-decomposition
35    IndexError(IndexError),
36}
37
38impl Display for DecomposeError {
39    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
40        let message = match self {
41            DecomposeError::Generic(m) => m,
42            DecomposeError::BoundaryError(b) => &format!("{b}"),
43            DecomposeError::IndexError(i) => &format!("{i}"),
44        };
45        write!(f, "{}", message)
46    }
47}
48
49impl Error for DecomposeError {}
50
51impl From<BoundaryError> for DecomposeError {
52    fn from(value: BoundaryError) -> Self {
53        DecomposeError::BoundaryError(value)
54    }
55}
56
57impl From<IndexError> for DecomposeError {
58    fn from(value: IndexError) -> Self {
59        DecomposeError::IndexError(value)
60    }
61}
62
63define_errors!(
64    (SetupError, "Occurs during setup of a new simulation"),
65    (CalcError, "General Calculation Error"),
66    (
67        TimeError,
68        "Error related to advancing the simulation time or displaying its progress"
69    ),
70    // (
71    //     DecomposeError,
72    //     "Error during decomposition of a SimulationDomain into multiple subdomains"
73    // ),
74    (DivisionError, "Errors related to a cell dividing process"),
75    (
76        DeathError,
77        "Errors occurring during the final death step of a cell"
78    ),
79    (
80        IndexError,
81        "Can occur internally when information is not present at expected place"
82    ),
83    (
84        RequestError,
85        "Ask the wrong object for information and receive this error"
86    ),
87    (
88        CommunicationError,
89        "Error which occurs during sending, receiving or transmitting information between threads"
90    ),
91    (BoundaryError, "Can occur during boundary calculation"),
92    (
93        ControllerError,
94        "Occurs when incorrectly applying a controller effect"
95    ),
96    (DrawingError, "Used to catch errors related to plotting"),
97    (
98        RngError,
99        "Can occur when generating distributions or drawing samples from them."
100    )
101);
102
103impl From<String> for TimeError {
104    fn from(value: String) -> Self {
105        TimeError(value)
106    }
107}
108
109impl From<std::io::Error> for DecomposeError {
110    fn from(value: std::io::Error) -> Self {
111        DecomposeError::BoundaryError(BoundaryError(format!("{}", value)))
112    }
113}
114
115impl From<CalcError> for SetupError {
116    fn from(value: CalcError) -> Self {
117        SetupError(format!("{}", value))
118    }
119}
120
121impl<E> From<plotters::drawing::DrawingAreaErrorKind<E>> for DrawingError
122where
123    E: Error + Send + Sync,
124{
125    fn from(drawing_error: plotters::drawing::DrawingAreaErrorKind<E>) -> DrawingError {
126        DrawingError(drawing_error.to_string())
127    }
128}
129
130/// For internal use: formats an error message to include a link to the bug tracker on github.
131#[doc(hidden)]
132#[macro_export]
133macro_rules! format_error_message(
134    (@function) => {
135        {
136            fn f() {}
137            let name = std::any::type_name_of_val(&f);
138            name.strip_suffix("::f").unwrap()
139        }
140    };
141    ($bug_title:expr, $error_msg:expr) => {
142        {//#[cfg(debug_assertions)]
143         //TODO think about enabling these debug_assertions (performance difference unclear to me)
144        let __cr_private_error = {
145            let title = $bug_title.replace(" ", "%20");
146            let mut body = String::from($error_msg);
147            body = body + &format!("%0A%0AFile: {}", file!());
148            body = body + &format!("%0ALine: {}", line!());
149            body = body + &format!("%0AColumn: {}", column!());
150            body = body.replace(" ", "%20");
151            format!("Internal Error in file {} function {}: +++ {} +++ Please file a bug-report: \
152                https://github.com/jonaspleyer/cellular_raza/issues/new?\
153                title={}&body={}",
154                format_error_message!(@function),
155                file!(),
156                $error_msg,
157                title,
158                body,
159            )
160        };
161        //#[cfg(not(debug_assertions))]
162        //let __cr_private_error = format!("Encountered internal error: {} with message: \
163        //    {} Run in debug mode for more details.",
164        //    $bug_title,
165        //    $error_msg
166        //);
167        __cr_private_error
168        }
169    };
170);