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