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