pub mod data_loader;
pub mod data_models;
pub mod data_validator;
pub mod traits;
pub use data_loader::DataLoader;
pub use data_models::{ClusterResult, OHLCV};
pub use data_validator::DataValidator;
pub use traits::ClusteringAlgorithm;
use thiserror::Error;
#[derive(Error, Debug)]
pub enum FormicaXError {
#[error("Data error: {0}")]
Data(#[from] DataError),
#[error("Clustering error: {0}")]
Clustering(#[from] ClusteringError),
#[error("Configuration error: {0}")]
Config(#[from] ConfigError),
#[error("Performance error: {0}")]
Performance(#[from] PerformanceError),
#[error("IO error: {0}")]
Io(#[from] std::io::Error),
#[error("CSV error: {0}")]
Csv(#[from] csv::Error),
#[error("Serialization error: {0}")]
Serialization(#[from] serde_json::Error),
#[error("DateTime error: {0}")]
DateTime(#[from] chrono::ParseError),
}
#[derive(Error, Debug)]
pub enum DataError {
#[error("Invalid CSV format: {message}")]
InvalidCsvFormat { message: String },
#[error("Missing required column: {column}")]
MissingColumn { column: String },
#[error("Invalid data type for column {column}: expected {expected}, got {actual}")]
InvalidDataType {
column: String,
expected: String,
actual: String,
},
#[error("Data validation failed: {message}")]
ValidationFailed { message: String },
#[error("Dataset is empty")]
EmptyDataset,
#[error(
"Insufficient data for clustering: need at least {min_points} points, got {actual_points}"
)]
InsufficientData {
min_points: usize,
actual_points: usize,
},
#[error("Invalid OHLCV data: {message}")]
InvalidOHLCV { message: String },
}
#[derive(Error, Debug)]
pub enum ClusteringError {
#[error("Algorithm failed to converge after {iterations} iterations")]
ConvergenceFailure { iterations: usize },
#[error("Invalid clustering parameters: {message}")]
InvalidParameters { message: String },
#[error("Algorithm error: {message}")]
AlgorithmError { message: String },
#[error("Memory allocation failed: {message}")]
MemoryError { message: String },
#[error("Numerical computation error: {message}")]
NumericalError { message: String },
}
#[derive(Error, Debug)]
pub enum ConfigError {
#[error("Invalid configuration value for {field}: {message}")]
InvalidValue { field: String, message: String },
#[error("Missing required configuration: {field}")]
MissingField { field: String },
#[error("Configuration validation failed: {message}")]
ValidationFailed { message: String },
}
#[derive(Error, Debug)]
pub enum PerformanceError {
#[error("SIMD operation failed: {message}")]
SimdError { message: String },
#[error("Parallel processing error: {message}")]
ParallelError { message: String },
#[error("Memory management error: {message}")]
MemoryError { message: String },
#[error("Operation timed out after {duration:?}")]
Timeout { duration: std::time::Duration },
}
pub type FormicaXResult<T> = Result<T, FormicaXError>;
#[cfg(test)]
mod tests {
use super::*;
use proptest::prelude::*;
#[test]
fn test_error_conversions() {
let io_error = std::io::Error::new(std::io::ErrorKind::NotFound, "File not found");
let formicax_error: FormicaXError = io_error.into();
assert!(matches!(formicax_error, FormicaXError::Io(_)));
let csv_error = csv::Error::from(std::io::Error::new(
std::io::ErrorKind::NotFound,
"CSV error",
));
let formicax_error: FormicaXError = csv_error.into();
assert!(matches!(formicax_error, FormicaXError::Csv(_)));
}
proptest! {
#[test]
fn test_data_error_creation(
column in "[a-zA-Z_][a-zA-Z0-9_]*",
message in "[a-zA-Z0-9 ]+"
) {
let error = DataError::MissingColumn { column: column.clone() };
assert!(error.to_string().contains(&column));
let error = DataError::ValidationFailed { message: message.clone() };
assert!(error.to_string().contains(&message));
}
}
#[test]
fn test_clustering_error_creation() {
let error = ClusteringError::ConvergenceFailure { iterations: 100 };
assert!(error.to_string().contains("100"));
let error = ClusteringError::InvalidParameters {
message: "k must be > 0".to_string(),
};
assert!(error.to_string().contains("k must be > 0"));
}
#[test]
fn test_config_error_creation() {
let error = ConfigError::InvalidValue {
field: "k".to_string(),
message: "must be positive".to_string(),
};
assert!(error.to_string().contains("k"));
assert!(error.to_string().contains("must be positive"));
}
#[test]
fn test_performance_error_creation() {
let duration = std::time::Duration::from_secs(30);
let error = PerformanceError::Timeout { duration };
assert!(error.to_string().contains("30"));
}
}