Skip to main content

scry_learn/
error.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2//! Error types for scry-learn.
3
4use std::fmt;
5
6/// Errors produced by scry-learn operations.
7#[derive(Debug)]
8#[non_exhaustive]
9pub enum ScryLearnError {
10    /// The dataset contains no samples.
11    EmptyDataset,
12
13    /// The input data contains NaN, Inf, or other non-finite values.
14    InvalidData(String),
15
16    /// A referenced column does not exist.
17    InvalidColumn(String),
18
19    /// Feature matrix dimensions do not match what the model expects.
20    ShapeMismatch {
21        /// Expected number of features.
22        expected: usize,
23        /// Actual number of features provided.
24        got: usize,
25    },
26
27    /// `predict()` or `transform()` called before `fit()`.
28    NotFitted,
29
30    /// An invalid hyperparameter was supplied.
31    InvalidParameter(String),
32
33    /// No convergence within the iteration limit.
34    ConvergenceFailure {
35        /// Number of iterations attempted.
36        iterations: usize,
37        /// Convergence tolerance.
38        tolerance: f64,
39    },
40
41    /// I/O error during file operations.
42    Io(std::io::Error),
43
44    /// CSV parsing error.
45    Csv(String),
46
47    /// A referenced feature index is out of bounds.
48    InvalidFeatureIndex(usize),
49}
50
51impl fmt::Display for ScryLearnError {
52    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
53        match self {
54            Self::EmptyDataset => f.write_str("dataset is empty — no samples to train on"),
55            Self::InvalidData(msg) => write!(f, "invalid data: {msg}"),
56            Self::InvalidColumn(col) => write!(f, "column not found: {col}"),
57            Self::ShapeMismatch { expected, got } => {
58                write!(f, "shape mismatch: expected {expected} features, got {got}")
59            }
60            Self::NotFitted => f.write_str("model has not been fitted — call .fit() first"),
61            Self::InvalidParameter(msg) => write!(f, "invalid parameter: {msg}"),
62            Self::ConvergenceFailure {
63                iterations,
64                tolerance,
65            } => {
66                write!(
67                    f,
68                    "failed to converge after {iterations} iterations (tolerance: {tolerance})"
69                )
70            }
71            Self::Io(err) => write!(f, "I/O error: {err}"),
72            Self::Csv(msg) => write!(f, "CSV error: {msg}"),
73            Self::InvalidFeatureIndex(idx) => write!(f, "invalid feature index: {idx}"),
74        }
75    }
76}
77
78impl std::error::Error for ScryLearnError {
79    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
80        match self {
81            Self::Io(err) => Some(err),
82            _ => None,
83        }
84    }
85}
86
87impl From<std::io::Error> for ScryLearnError {
88    fn from(err: std::io::Error) -> Self {
89        Self::Io(err)
90    }
91}
92
93/// Convenience type alias.
94pub type Result<T> = std::result::Result<T, ScryLearnError>;