Skip to main content

irithyll/
error.rs

1//! Error types for Irithyll.
2
3use thiserror::Error;
4
5// ---------------------------------------------------------------------------
6// ConfigError -- structured sub-enum for configuration validation
7// ---------------------------------------------------------------------------
8
9/// Structured error for configuration validation failures.
10///
11/// Instead of opaque strings, each variant carries the parameter name and
12/// constraint so callers can programmatically inspect what went wrong.
13#[derive(Debug, Clone, Error)]
14pub enum ConfigError {
15    /// A parameter value is outside its valid range.
16    ///
17    /// # Examples
18    ///
19    /// ```text
20    /// n_steps must be > 0 (got 0)
21    /// learning_rate must be in (0, 1] (got 1.5)
22    /// ```
23    #[error("{param} {constraint} (got {value})")]
24    OutOfRange {
25        /// The parameter name (e.g. `"n_steps"`, `"drift_detector.Adwin.delta"`).
26        param: &'static str,
27        /// The constraint that was violated (e.g. `"must be > 0"`).
28        constraint: &'static str,
29        /// The actual value that was provided.
30        value: String,
31    },
32
33    /// A parameter is invalid for a structural reason, typically involving
34    /// a relationship between two parameters.
35    ///
36    /// # Examples
37    ///
38    /// ```text
39    /// split_reeval_interval must be >= grace_period (200), got 50
40    /// drift_detector.Ddm.drift_level must be > warning_level (3.0), got 2.0
41    /// ```
42    #[error("{param} {reason}")]
43    Invalid {
44        /// The parameter name.
45        param: &'static str,
46        /// Why the value is invalid.
47        reason: String,
48    },
49}
50
51impl ConfigError {
52    /// Convenience for the common "value out of range" case.
53    pub fn out_of_range(
54        param: &'static str,
55        constraint: &'static str,
56        value: impl ToString,
57    ) -> Self {
58        ConfigError::OutOfRange {
59            param,
60            constraint,
61            value: value.to_string(),
62        }
63    }
64
65    /// Convenience for the "invalid relationship" case.
66    pub fn invalid(param: &'static str, reason: impl Into<String>) -> Self {
67        ConfigError::Invalid {
68            param,
69            reason: reason.into(),
70        }
71    }
72}
73
74// ---------------------------------------------------------------------------
75// IrithyllError -- top-level error enum
76// ---------------------------------------------------------------------------
77
78/// Top-level error type for the Irithyll crate.
79#[derive(Debug, Error)]
80pub enum IrithyllError {
81    /// Configuration validation failed.
82    #[error("invalid configuration: {0}")]
83    InvalidConfig(#[from] ConfigError),
84
85    /// Not enough data to perform the requested operation.
86    #[error("insufficient data: {0}")]
87    InsufficientData(String),
88
89    /// Feature dimension mismatch between sample and model.
90    #[error("dimension mismatch: expected {expected}, got {got}")]
91    DimensionMismatch { expected: usize, got: usize },
92
93    /// Model has not been trained yet.
94    #[error("model not trained")]
95    NotTrained,
96
97    /// Serialization or deserialization failed.
98    #[error("serialization error: {0}")]
99    Serialization(String),
100
101    /// Async channel closed unexpectedly.
102    #[error("channel closed")]
103    ChannelClosed,
104}
105
106pub type Result<T> = std::result::Result<T, IrithyllError>;