1use thiserror::Error;
2#[cfg(feature = "python")]
3pub mod python;
4
5pub type Result<T> = std::result::Result<T, RadiateError>;
6
7#[derive(Copy, Clone, Debug, PartialEq, Eq)]
8pub enum Code {
9 InvalidConfig,
10 Engine,
11 Codec,
12 Evaluation,
13 Genome,
14 Fitness,
15 Metric,
16 Expr,
17 Other,
18 Io,
19 Python,
20 Multiple,
21 Context,
22 IO,
23}
24
25#[derive(Error, Debug)]
26pub enum RadiateError {
27 #[error("Builder error: {0}")]
28 Builder(String),
29
30 #[error("Engine error: {0}")]
31 Engine(String),
32
33 #[error("Genome error: {0}")]
34 Genome(String),
35
36 #[error("Codec error: {0}")]
37 Codec(String),
38
39 #[error("Evaluation error: {0}")]
40 Evaluation(String),
41
42 #[error("Invalid fitness: {0}")]
43 Fitness(String),
44
45 #[error("Metric error: {0}")]
46 Metric(String),
47
48 #[error("Expression error: {0}")]
49 Expr(String),
50
51 #[cfg(feature = "python")]
52 #[error("Python error: {0}")]
53 Python(#[from] pyo3::PyErr),
54
55 #[error("Multiple errors:\n{0}")]
56 Multiple(String),
57
58 #[error("Other error: {0}")]
59 Other(String),
60
61 #[error("{context}\nCaused by: {source}")]
62 Context {
63 context: String,
64 #[source]
65 source: Box<RadiateError>,
66 },
67
68 #[error("I/O error: {0}")]
69 IO(#[from] std::io::Error),
70
71 #[error("Formatting error: {0}")]
72 Fmt(#[from] std::fmt::Error),
73}
74
75impl RadiateError {
76 pub fn code(&self) -> Code {
77 match self {
78 RadiateError::Builder { .. } => Code::InvalidConfig,
79 RadiateError::Engine { .. } => Code::Engine,
80 RadiateError::Genome { .. } => Code::Genome,
81 RadiateError::Codec { .. } => Code::Codec,
82 RadiateError::Fitness { .. } => Code::Fitness,
83 RadiateError::Metric { .. } => Code::Metric,
84 RadiateError::Expr { .. } => Code::Expr,
85 RadiateError::Evaluation { .. } => Code::Evaluation,
86 RadiateError::Other(_) => Code::Other,
87 #[cfg(feature = "python")]
88 RadiateError::Python { .. } => Code::Python,
89 RadiateError::Multiple(_) => Code::Multiple,
90 RadiateError::Context { .. } => Code::Context,
91 RadiateError::IO(_) => Code::IO,
92 RadiateError::Fmt(_) => Code::Other,
93 }
94 }
95 pub fn context(self, msg: impl Into<String>) -> Self {
96 RadiateError::Context {
97 context: msg.into(),
98 source: Box::new(self),
99 }
100 }
101
102 pub fn leaf_code(&self) -> Code {
109 match self {
110 RadiateError::Context { source, .. } => source.leaf_code(),
111 other => other.code(),
112 }
113 }
114}
115
116pub trait ResultExt<T> {
117 fn context(self, msg: impl Into<String>) -> Result<T>;
118 fn with_context<F: FnOnce() -> String>(self, f: F) -> Result<T>;
119}
120
121impl<T, E: Into<RadiateError>> ResultExt<T> for std::result::Result<T, E> {
122 fn context(self, msg: impl Into<String>) -> Result<T> {
123 self.map_err(|e| e.into().context(msg))
124 }
125
126 fn with_context<F: FnOnce() -> String>(self, f: F) -> Result<T> {
127 self.map_err(|e| e.into().context(f()))
128 }
129}
130
131#[doc(hidden)]
132pub mod __private {
133 #[inline]
134 #[cold]
135 #[must_use]
136 pub fn must_use<E>(e: E) -> E {
137 e
138 }
139}
140
141#[macro_export]
142macro_rules! radiate_err {
143 (Builder: $fmt:literal $(, $arg:expr)* $(,)?) => {
145 $crate::__private::must_use($crate::RadiateError::Builder(format!($fmt, $($arg),*)))
146 };
147 (Engine: $fmt:literal $(, $arg:expr)* $(,)?) => {
148 $crate::__private::must_use($crate::RadiateError::Engine(format!($fmt, $($arg),*)))
149 };
150 (Genome: $fmt:literal $(, $arg:expr)* $(,)?) => {
151 $crate::__private::must_use($crate::RadiateError::Genome(format!($fmt, $($arg),*)))
152 };
153 (Codec: $fmt:literal $(, $arg:expr)* $(,)?) => {
154 $crate::__private::must_use($crate::RadiateError::Codec(format!($fmt, $($arg),*)))
155 };
156 (Evaluation: $fmt:literal $(, $arg:expr)* $(,)?) => {
157 $crate::__private::must_use($crate::RadiateError::Evaluation(format!($fmt, $($arg),*)))
158 };
159 (Python: $fmt:literal $(, $arg:expr)* $(,)?) => {
160 $crate::__private::must_use(pyo3::PyErr::new::<pyo3::exceptions::PyException, _>(format!($fmt, $($arg),*)))
161 };
162 (Metric: $fmt:literal $(, $arg:expr)* $(,)?) => {
163 $crate::__private::must_use($crate::RadiateError::Metric(format!($fmt, $($arg),*)))
164 };
165 (Expr: $fmt:literal $(, $arg:expr)* $(,)?) => {
166 $crate::__private::must_use($crate::RadiateError::Expr(format!($fmt, $($arg),*)))
167 };
168
169 (Context: $msg:expr, $source:expr $(,)?) => {
171 $crate::__private::must_use($source.into().context($msg))
172 };
173
174 (IO: $fmt:literal $(, $arg:expr)* $(,)?) => {
175 $crate::__private::must_use($crate::RadiateError::IO(format!($fmt, $($arg),*)))
176 };
177 (Fmt: $fmt:literal $(, $arg:expr)* $(,)?) => {
178 $crate::__private::must_use($crate::RadiateError::Fmt(format!($fmt, $($arg),*)))
179 };
180
181 (Builder: $msg:expr $(,)?) => {
183 $crate::__private::must_use($crate::RadiateError::Builder($msg.to_string()))
184 };
185 (Engine: $msg:expr $(,)?) => {
186 $crate::__private::must_use($crate::RadiateError::Engine($msg.to_string()))
187 };
188 (Genome: $msg:expr $(,)?) => {
189 $crate::__private::must_use($crate::RadiateError::Genome($msg.to_string()))
190 };
191 (Codec: $msg:expr $(,)?) => {
192 $crate::__private::must_use($crate::RadiateError::Codec($msg.to_string()))
193 };
194 (Evaluation: $msg:expr $(,)?) => {
195 $crate::__private::must_use($crate::RadiateError::Evaluation($msg.to_string()))
196 };
197 (Python: $msg:expr $(,)?) => {
198 $crate::__private::must_use(pyo3::PyErr::new::<pyo3::exceptions::PyException, _>($msg.to_string()))
199 };
200 (Metric: $msg:expr $(,)?) => {
201 $crate::__private::must_use($crate::RadiateError::Metric($msg.to_string()))
202 };
203 (Expr: $msg:expr $(,)?) => {
204 $crate::__private::must_use($crate::RadiateError::Expr($msg.to_string()))
205 };
206 (IO: $msg:expr $(,)?) => {
207 $crate::__private::must_use($crate::RadiateError::IO($msg.to_string()))
208 };
209 (Fmt: $msg:expr $(,)?) => {
210 $crate::__private::must_use($crate::RadiateError::Fmt($msg.to_string()))
211 };
212
213 ($msg:expr $(,)?) => {
215 $crate::__private::must_use($crate::RadiateError::Engine($msg.to_string()))
216 };
217}
218
219#[macro_export]
220macro_rules! radiate_bail {
221 ($($tt:tt)+) => { return Err($crate::radiate_err!($($tt)+)) };
222}
223
224#[macro_export]
225macro_rules! ensure {
226 ($cond:expr, $($tt:tt)+) => {
227 if !$cond { $crate::radiate_bail!($($tt)+); }
228 };
229}