1#[cfg(feature = "alloc")]
9use alloc::string::String;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
17pub enum FormatError {
18 BadMagic,
20 UnsupportedVersion,
22 Truncated,
24 Unaligned,
26 InvalidNodeIndex,
28 InvalidFeatureIndex,
30 MisalignedTreeOffset,
32}
33
34impl core::fmt::Display for FormatError {
35 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
36 match self {
37 FormatError::BadMagic => write!(f, "bad magic: expected \"IRIT\""),
38 FormatError::UnsupportedVersion => write!(f, "unsupported format version"),
39 FormatError::Truncated => write!(f, "buffer truncated"),
40 FormatError::Unaligned => write!(f, "buffer not 4-byte aligned"),
41 FormatError::InvalidNodeIndex => write!(f, "node child index out of bounds"),
42 FormatError::InvalidFeatureIndex => write!(f, "feature index exceeds n_features"),
43 FormatError::MisalignedTreeOffset => {
44 write!(f, "tree offset not aligned to node size")
45 }
46 }
47 }
48}
49
50#[cfg(feature = "alloc")]
61#[derive(Debug, Clone)]
62pub enum ConfigError {
63 OutOfRange {
72 param: &'static str,
74 constraint: &'static str,
76 value: String,
78 },
79
80 Invalid {
90 param: &'static str,
92 reason: String,
94 },
95}
96
97#[cfg(feature = "alloc")]
98impl ConfigError {
99 pub fn out_of_range(
101 param: &'static str,
102 constraint: &'static str,
103 value: impl core::fmt::Display,
104 ) -> Self {
105 use alloc::format;
106 ConfigError::OutOfRange {
107 param,
108 constraint,
109 value: format!("{}", value),
110 }
111 }
112
113 pub fn invalid(param: &'static str, reason: impl Into<String>) -> Self {
115 ConfigError::Invalid {
116 param,
117 reason: reason.into(),
118 }
119 }
120}
121
122#[cfg(feature = "alloc")]
123impl core::fmt::Display for ConfigError {
124 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
125 match self {
126 ConfigError::OutOfRange {
127 param,
128 constraint,
129 value,
130 } => write!(f, "{} {} (got {})", param, constraint, value),
131 ConfigError::Invalid { param, reason } => write!(f, "{} {}", param, reason),
132 }
133 }
134}
135
136#[cfg(feature = "std")]
138impl std::error::Error for ConfigError {}
139
140#[cfg(feature = "alloc")]
148#[derive(Debug)]
149pub enum IrithyllError {
150 InvalidConfig(ConfigError),
152 InsufficientData(String),
154 DimensionMismatch {
156 expected: usize,
158 got: usize,
160 },
161 NotTrained,
163}
164
165#[cfg(feature = "alloc")]
166impl core::fmt::Display for IrithyllError {
167 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
168 match self {
169 IrithyllError::InvalidConfig(e) => write!(f, "invalid configuration: {}", e),
170 IrithyllError::InsufficientData(msg) => write!(f, "insufficient data: {}", msg),
171 IrithyllError::DimensionMismatch { expected, got } => {
172 write!(f, "dimension mismatch: expected {}, got {}", expected, got)
173 }
174 IrithyllError::NotTrained => write!(f, "model not trained"),
175 }
176 }
177}
178
179#[cfg(feature = "alloc")]
180impl From<ConfigError> for IrithyllError {
181 fn from(e: ConfigError) -> Self {
182 IrithyllError::InvalidConfig(e)
183 }
184}
185
186#[cfg(feature = "alloc")]
188pub type Result<T> = core::result::Result<T, IrithyllError>;
189
190#[cfg(test)]
195mod tests {
196 use super::*;
197 use alloc::string::ToString;
198
199 #[test]
200 fn format_error_display() {
201 assert_eq!(
202 FormatError::BadMagic.to_string(),
203 "bad magic: expected \"IRIT\""
204 );
205 assert_eq!(FormatError::Truncated.to_string(), "buffer truncated");
206 }
207
208 #[cfg(feature = "alloc")]
209 #[test]
210 fn config_error_out_of_range_display() {
211 let e = ConfigError::out_of_range("n_steps", "must be > 0", 0);
212 assert_eq!(e.to_string(), "n_steps must be > 0 (got 0)");
213 }
214
215 #[cfg(feature = "alloc")]
216 #[test]
217 fn config_error_invalid_display() {
218 let e = ConfigError::invalid(
219 "split_reeval_interval",
220 "must be >= grace_period (200), got 50",
221 );
222 assert!(e.to_string().contains("split_reeval_interval"));
223 assert!(e.to_string().contains("must be >= grace_period"));
224 }
225
226 #[cfg(feature = "alloc")]
227 #[test]
228 fn irithyll_error_from_config_error() {
229 let ce = ConfigError::out_of_range("learning_rate", "must be in (0, 1]", 1.5);
230 let ie: IrithyllError = ce.into();
231 let msg = ie.to_string();
232 assert!(msg.contains("invalid configuration"));
233 assert!(msg.contains("learning_rate"));
234 }
235
236 #[cfg(feature = "alloc")]
237 #[test]
238 fn irithyll_error_dimension_mismatch() {
239 let e = IrithyllError::DimensionMismatch {
240 expected: 10,
241 got: 5,
242 };
243 assert_eq!(e.to_string(), "dimension mismatch: expected 10, got 5");
244 }
245
246 #[cfg(feature = "alloc")]
247 #[test]
248 fn irithyll_error_not_trained() {
249 assert_eq!(IrithyllError::NotTrained.to_string(), "model not trained");
250 }
251}