1use smartstring::alias::String as SString;
2use thiserror::Error as ThisError;
3
4use crate::Key;
5
6#[derive(Debug, ThisError)]
7pub enum Error {
8 #[error("Empty dataset")]
9 EmptyData,
10 #[error("Dataset size doesn't match expected: {0}, get: {1}")]
11 DataSetSizeDoesntMatch(usize, usize),
12 #[error("Dataset size doesn't match idx: {0}, size of data: {1}")]
13 IndexOutOfRange(usize, usize),
14 #[error("Indexes are out of order expected: {0:?}, get: {1:?}")]
15 IndexOutOfOrder(Vec<Key>, Vec<Key>),
16 #[error("Cannot find candidate: {0}")]
17 Candidate(SString),
18 #[error("Cannot find key: {0}")]
19 NotFound(Key),
20 #[error("Column already exists: {0}")]
21 ColumnAlreadyExists(Key),
22 #[error("Cannot broadcast data")]
23 CannotBroadcast,
24 #[error("Cannot find feature: {0}")]
25 FeatureSearch(SString),
26 #[error("Invalid operation for feature: {operation} with features: {features:?}")]
27 InvalidOperation {
28 operation: SString,
29 features: Vec<SString>,
30 },
31 #[error("Unknown error: {0}")]
32 UnknownError(String),
33 #[error("IOError {0}")]
34 IOError(#[from] std::io::Error),
35 #[cfg(feature = "python")]
36 #[error("PyO3 error: {0}")]
37 PyO3(#[from] pyo3::prelude::PyErr),
38 #[error("{0}")]
39 Shape(#[from] ndarray::ShapeError),
40 #[error("Cannot find feature: {0}")]
41 MissingField(SString),
42 #[cfg(feature = "polars-df")]
43 #[error("Polars error {0}")]
44 Polars(#[from] polars::error::PolarsError),
45
46 #[error("Filter expression: {0}")]
47 Filter(#[from] crate::filter::error::Error),
48}
49
50impl PartialEq for Error {
51 fn eq(&self, other: &Self) -> bool {
52 match (self, other) {
53 (Self::EmptyData, Self::EmptyData) => true,
54 (Self::NotFound(a), Self::NotFound(b)) => a == b,
55 (Self::DataSetSizeDoesntMatch(a, b), Self::DataSetSizeDoesntMatch(c, d)) => {
56 a == c && b == d
57 }
58 (Self::IndexOutOfRange(a, b), Self::IndexOutOfRange(c, d)) => a == c && b == d,
59 (Self::IndexOutOfOrder(a, b), Self::IndexOutOfOrder(c, d)) => a == c && b == d,
60 (Self::Candidate(a), Self::Candidate(b)) => a == b,
61 (Self::FeatureSearch(a), Self::FeatureSearch(b)) => a == b,
62 (Self::MissingField(a), Self::MissingField(b)) => a == b,
63 (Self::UnknownError(a), Self::UnknownError(b)) => a == b,
64 (
65 Self::InvalidOperation {
66 operation: a,
67 features: b,
68 },
69 Self::InvalidOperation {
70 operation: c,
71 features: d,
72 },
73 ) => a == c && b == d,
74 (Self::IOError(a), Self::IOError(b)) => a.kind() == b.kind(),
75 (Self::ColumnAlreadyExists(a), Self::ColumnAlreadyExists(b)) => a == b,
76 (Self::CannotBroadcast, Self::CannotBroadcast) => true,
77 #[cfg(feature = "python")]
78 (Self::PyO3(a), Self::PyO3(b)) => a.to_string() == b.to_string(),
79 #[cfg(feature = "polars-df")]
80 (Self::Polars(a), Self::Polars(b)) => a.to_string() == b.to_string(),
81 _ => false,
82 }
83 }
84}
85
86#[cfg(test)]
87mod test {
88 #[cfg(feature = "python")]
89 use pyo3::{exceptions::PyValueError, PyErr};
90
91 use super::*;
92 #[test]
93 fn test_error() {
94 let err1 = Error::EmptyData;
95 assert_eq!(err1, Error::EmptyData);
96 let err = Error::DataSetSizeDoesntMatch(1, 2);
97 assert_eq!(err, Error::DataSetSizeDoesntMatch(1, 2));
98 assert_ne!(err1, err);
99 let err = Error::IndexOutOfRange(1, 2);
100 assert_eq!(err, Error::IndexOutOfRange(1, 2));
101 let err = Error::Candidate("test".into());
102 assert_eq!(err, Error::Candidate("test".into()));
103 let err = Error::FeatureSearch("test".into());
104 assert_eq!(err, Error::FeatureSearch("test".into()));
105 let err = Error::UnknownError("test".into());
106 assert_eq!(err, Error::UnknownError("test".into()));
107 let err = Error::MissingField("test".into());
108 assert_eq!(err, Error::MissingField("test".into()));
109 assert_eq!(
110 Error::NotFound("test".into()),
111 Error::NotFound("test".into())
112 );
113 assert_eq!(Error::CannotBroadcast, Error::CannotBroadcast);
114 assert_eq!(
115 Error::ColumnAlreadyExists("test".into()),
116 Error::ColumnAlreadyExists("test".into())
117 );
118 assert_eq!(
119 Error::IndexOutOfOrder(vec!["test".into()], vec!["test".into()]),
120 Error::IndexOutOfOrder(vec!["test".into()], vec!["test".into()])
121 );
122 let err = Error::IOError(std::io::Error::new(std::io::ErrorKind::Other, "test"));
123 assert_eq!(
124 err,
125 Error::IOError(std::io::Error::new(std::io::ErrorKind::Other, "test"))
126 );
127 let err = Error::InvalidOperation {
128 operation: "test".into(),
129 features: vec!["test".into()],
130 };
131 assert_eq!(
132 err,
133 Error::InvalidOperation {
134 operation: "test".into(),
135 features: vec!["test".into()],
136 }
137 );
138 #[cfg(feature = "python")]
139 {
140 let err = Error::PyO3(PyErr::new::<PyValueError, _>("foo"));
141 assert_eq!(err, Error::PyO3(PyErr::new::<PyValueError, _>("foo")));
142 }
143 #[cfg(feature = "polars-df")]
144 {
145 let err = Error::Polars(polars::error::PolarsError::ColumnNotFound("e".into()));
146 assert_eq!(
147 err,
148 Error::Polars(polars::error::PolarsError::ColumnNotFound("e".into()))
149 );
150 }
151 }
152}