use smartstring::alias::String as SString;
use thiserror::Error as ThisError;
use crate::Key;
#[derive(Debug, ThisError)]
pub enum Error {
#[error("Empty dataset")]
EmptyData,
#[error("Dataset size doesn't match expected: {0}, get: {1}")]
DataSetSizeDoesntMatch(usize, usize),
#[error("Dataset size doesn't match idx: {0}, size of data: {1}")]
IndexOutOfRange(usize, usize),
#[error("Indexes are out of order expected: {0:?}, get: {1:?}")]
IndexOutOfOrder(Vec<Key>, Vec<Key>),
#[error("Cannot find candidate: {0}")]
Candidate(SString),
#[error("Cannot find key: {0}")]
NotFound(Key),
#[error("Column already exists: {0}")]
ColumnAlreadyExists(Key),
#[error("Cannot broadcast data")]
CannotBroadcast,
#[error("Cannot find feature: {0}")]
FeatureSearch(SString),
#[error("Invalid operation for feature: {operation} with features: {features:?}")]
InvalidOperation {
operation: SString,
features: Vec<SString>,
},
#[error("Unknown error: {0}")]
UnknownError(String),
#[error("IOError {0}")]
IOError(#[from] std::io::Error),
#[cfg(feature = "python")]
#[error("PyO3 error: {0}")]
PyO3(#[from] pyo3::prelude::PyErr),
#[error("{0}")]
Shape(#[from] ndarray::ShapeError),
}
impl PartialEq for Error {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::EmptyData, Self::EmptyData) => true,
(Self::NotFound(a), Self::NotFound(b)) => a == b,
(Self::DataSetSizeDoesntMatch(a, b), Self::DataSetSizeDoesntMatch(c, d)) => {
a == c && b == d
}
(Self::IndexOutOfRange(a, b), Self::IndexOutOfRange(c, d)) => a == c && b == d,
(Self::IndexOutOfOrder(a, b), Self::IndexOutOfOrder(c, d)) => a == c && b == d,
(Self::Candidate(a), Self::Candidate(b)) => a == b,
(Self::FeatureSearch(a), Self::FeatureSearch(b)) => a == b,
(Self::UnknownError(a), Self::UnknownError(b)) => a == b,
(
Self::InvalidOperation {
operation: a,
features: b,
},
Self::InvalidOperation {
operation: c,
features: d,
},
) => a == c && b == d,
(Self::IOError(a), Self::IOError(b)) => a.kind() == b.kind(),
(Self::ColumnAlreadyExists(a), Self::ColumnAlreadyExists(b)) => a == b,
(Self::CannotBroadcast, Self::CannotBroadcast) => true,
#[cfg(feature = "python")]
(Self::PyO3(a), Self::PyO3(b)) => a.to_string() == b.to_string(),
_ => false,
}
}
}
#[cfg(test)]
mod test {
#[cfg(feature = "python")]
use pyo3::{exceptions::PyValueError, PyErr};
use super::*;
#[test]
fn test_error() {
let err1 = Error::EmptyData;
assert_eq!(err1, Error::EmptyData);
let err = Error::DataSetSizeDoesntMatch(1, 2);
assert_eq!(err, Error::DataSetSizeDoesntMatch(1, 2));
assert_ne!(err1, err);
let err = Error::IndexOutOfRange(1, 2);
assert_eq!(err, Error::IndexOutOfRange(1, 2));
let err = Error::Candidate("test".into());
assert_eq!(err, Error::Candidate("test".into()));
let err = Error::FeatureSearch("test".into());
assert_eq!(err, Error::FeatureSearch("test".into()));
let err = Error::UnknownError("test".into());
assert_eq!(err, Error::UnknownError("test".into()));
assert_eq!(
Error::NotFound("test".into()),
Error::NotFound("test".into())
);
assert_eq!(Error::CannotBroadcast, Error::CannotBroadcast);
assert_eq!(
Error::ColumnAlreadyExists("test".into()),
Error::ColumnAlreadyExists("test".into())
);
assert_eq!(
Error::IndexOutOfOrder(vec!["test".into()], vec!["test".into()]),
Error::IndexOutOfOrder(vec!["test".into()], vec!["test".into()])
);
let err = Error::IOError(std::io::Error::new(std::io::ErrorKind::Other, "test"));
assert_eq!(
err,
Error::IOError(std::io::Error::new(std::io::ErrorKind::Other, "test"))
);
let err = Error::InvalidOperation {
operation: "test".into(),
features: vec!["test".into()],
};
assert_eq!(
err,
Error::InvalidOperation {
operation: "test".into(),
features: vec!["test".into()],
}
);
#[cfg(feature = "python")]
{
let err = Error::PyO3(PyErr::new::<PyValueError, _>("foo"));
assert_eq!(err, Error::PyO3(PyErr::new::<PyValueError, _>("foo")));
}
}
}