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 Other,
16 Io,
17 Python,
18 Multiple,
19 Context,
20}
21
22#[derive(Error, Debug)]
23pub enum RadiateError {
24 #[error("Builder error: {0}")]
25 Builder(String),
26
27 #[error("Engine error: {0}")]
28 Engine(String),
29
30 #[error("Genome error: {0}")]
31 Genome(String),
32
33 #[error("Codec error: {0}")]
34 Codec(String),
35
36 #[error("Evaluation error: {0}")]
37 Evaluation(String),
38
39 #[error("Invalid fitness: {0}")]
40 Fitness(String),
41
42 #[cfg(feature = "python")]
43 #[error("Python error: {0}")]
44 Python(#[from] pyo3::PyErr),
45
46 #[error("Multiple errors:\n{0}")]
47 Multiple(String),
48
49 #[error("Other error: {0}")]
50 Other(String),
51
52 #[error("{context}\nCaused by: {source}")]
53 Context {
54 context: String,
55 #[source]
56 source: Box<RadiateError>,
57 },
58}
59
60impl RadiateError {
61 pub fn new_builder(msg: impl Into<String>) -> Self {
62 RadiateError::Builder(msg.into())
63 }
64
65 pub fn new_fitness(msg: impl Into<String>) -> Self {
66 RadiateError::Fitness(msg.into())
67 }
68}
69
70impl RadiateError {
71 pub fn code(&self) -> Code {
72 match self {
73 RadiateError::Builder { .. } => Code::InvalidConfig,
74 RadiateError::Engine { .. } => Code::Engine,
75 RadiateError::Genome { .. } => Code::Genome,
76 RadiateError::Codec { .. } => Code::Codec,
77 RadiateError::Fitness { .. } => Code::Fitness,
78 RadiateError::Evaluation { .. } => Code::Evaluation,
79 RadiateError::Other(_) => Code::Other,
80 #[cfg(feature = "python")]
81 RadiateError::Python { .. } => Code::Python,
82 RadiateError::Multiple(_) => Code::Multiple,
83 RadiateError::Context { .. } => Code::Context,
84 }
85 }
86 pub fn context(self, msg: impl Into<String>) -> Self {
87 RadiateError::Context {
88 context: msg.into(),
89 source: Box::new(self),
90 }
91 }
92}
93
94pub trait ResultExt<T> {
95 fn context(self, msg: impl Into<String>) -> Result<T>;
96 fn with_context<F: FnOnce() -> String>(self, f: F) -> Result<T>;
97}
98
99impl<T, E: Into<RadiateError>> ResultExt<T> for std::result::Result<T, E> {
100 fn context(self, msg: impl Into<String>) -> Result<T> {
101 self.map_err(|e| e.into().context(msg))
102 }
103
104 fn with_context<F: FnOnce() -> String>(self, f: F) -> Result<T> {
105 self.map_err(|e| e.into().context(f()))
106 }
107}
108
109#[doc(hidden)]
110pub mod __private {
111 #[inline]
112 #[cold]
113 #[must_use]
114 pub fn must_use<E>(e: E) -> E {
115 e
116 }
117}
118
119#[macro_export]
120macro_rules! radiate_err {
121 (Builder: $fmt:literal $(, $arg:expr)* $(,)?) => {
123 $crate::__private::must_use($crate::RadiateError::Builder(format!($fmt, $($arg),*)))
124 };
125 (Engine: $fmt:literal $(, $arg:expr)* $(,)?) => {
126 $crate::__private::must_use($crate::RadiateError::Engine(format!($fmt, $($arg),*)))
127 };
128 (Genome: $fmt:literal $(, $arg:expr)* $(,)?) => {
129 $crate::__private::must_use($crate::RadiateError::Genome(format!($fmt, $($arg),*)))
130 };
131 (Codec: $fmt:literal $(, $arg:expr)* $(,)?) => {
132 $crate::__private::must_use($crate::RadiateError::Codec(format!($fmt, $($arg),*)))
133 };
134 (Evaluation: $fmt:literal $(, $arg:expr)* $(,)?) => {
135 $crate::__private::must_use($crate::RadiateError::Evaluation(format!($fmt, $($arg),*)))
136 };
137 (Python: $fmt:literal $(, $arg:expr)* $(,)?) => {
138 $crate::__private::must_use(pyo3::PyErr::new::<pyo3::exceptions::PyException, _>(format!($fmt, $($arg),*)))
139 };
140
141 (Builder: $msg:expr $(,)?) => {
143 $crate::__private::must_use($crate::RadiateError::Builder($msg.to_string()))
144 };
145 (Engine: $msg:expr $(,)?) => {
146 $crate::__private::must_use($crate::RadiateError::Engine($msg.to_string()))
147 };
148 (Genome: $msg:expr $(,)?) => {
149 $crate::__private::must_use($crate::RadiateError::Genome($msg.to_string()))
150 };
151 (Codec: $msg:expr $(,)?) => {
152 $crate::__private::must_use($crate::RadiateError::Codec($msg.to_string()))
153 };
154 (Evaluation: $msg:expr $(,)?) => {
155 $crate::__private::must_use($crate::RadiateError::Evaluation($msg.to_string()))
156 };
157
158 ($msg:expr $(,)?) => {
160 $crate::__private::must_use($crate::RadiateError::Engine($msg.to_string()))
161 };
162}
163
164#[macro_export]
165macro_rules! radiate_bail {
166 ($($tt:tt)+) => { return Err($crate::radiate_err!($($tt)+)) };
167}
168
169#[macro_export]
170macro_rules! ensure {
171 ($cond:expr, $($tt:tt)+) => {
172 if !$cond { $crate::radiate_bail!($($tt)+); }
173 };
174}