use std::fmt;
use std::io;
use std::path::PathBuf;
pub type Result<T> = std::result::Result<T, BenchError>;
#[derive(Debug, thiserror::Error)]
pub enum BenchError {
#[error("I/O error: {0}")]
Io(#[from] io::Error),
#[error("Serialization error: {0}")]
Serialization(#[from] serde_json::Error),
#[error("Profiler error: {source}")]
Profiler {
source: ProfilerErrorKind,
},
#[error("Benchmark execution error: {message}")]
BenchmarkExecution {
message: String,
benchmark_name: Option<String>,
},
#[error("Report generation error: {format} - {message}")]
ReportGeneration {
format: String,
message: String,
},
#[error("Regression detection error: {0}")]
RegressionDetection(String),
#[error("Baseline error for '{path}': {message}")]
Baseline {
path: PathBuf,
message: String,
},
#[error("Comparison error: {0}")]
Comparison(String),
#[error("Invalid configuration: {0}")]
InvalidConfiguration(String),
#[error("Missing dependency: {dependency} (enable feature: {feature})")]
MissingDependency {
dependency: String,
feature: String,
},
#[error("Scenario '{scenario}' failed: {message}")]
ScenarioFailed {
scenario: String,
message: String,
},
#[error("System resource error: {0}")]
SystemResource(String),
#[error("Memory profiling error: {0}")]
MemoryProfiling(String),
#[error("CPU profiling error: {0}")]
CpuProfiling(String),
#[error("Flamegraph generation error: {0}")]
Flamegraph(String),
#[error("Data validation error: {0}")]
DataValidation(String),
#[error("Operation timed out after {seconds} seconds")]
Timeout {
seconds: u64,
},
#[cfg(feature = "raster")]
#[error("OxiGDAL core error: {0}")]
Core(#[from] oxigdal_core::error::OxiGdalError),
#[error("{0}")]
Other(String),
}
#[derive(Debug)]
pub enum ProfilerErrorKind {
InitializationFailed(String),
StartFailed(String),
StopFailed(String),
CollectionFailed(String),
ReportGenerationFailed(String),
UnsupportedFeature(String),
}
impl fmt::Display for ProfilerErrorKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::InitializationFailed(msg) => write!(f, "initialization failed: {msg}"),
Self::StartFailed(msg) => write!(f, "start failed: {msg}"),
Self::StopFailed(msg) => write!(f, "stop failed: {msg}"),
Self::CollectionFailed(msg) => write!(f, "collection failed: {msg}"),
Self::ReportGenerationFailed(msg) => write!(f, "report generation failed: {msg}"),
Self::UnsupportedFeature(msg) => write!(f, "unsupported feature: {msg}"),
}
}
}
impl std::error::Error for ProfilerErrorKind {}
impl BenchError {
pub fn profiler_init<S: Into<String>>(message: S) -> Self {
Self::Profiler {
source: ProfilerErrorKind::InitializationFailed(message.into()),
}
}
pub fn profiler_start<S: Into<String>>(message: S) -> Self {
Self::Profiler {
source: ProfilerErrorKind::StartFailed(message.into()),
}
}
pub fn profiler_stop<S: Into<String>>(message: S) -> Self {
Self::Profiler {
source: ProfilerErrorKind::StopFailed(message.into()),
}
}
pub fn profiler_collect<S: Into<String>>(message: S) -> Self {
Self::Profiler {
source: ProfilerErrorKind::CollectionFailed(message.into()),
}
}
pub fn benchmark_execution<S: Into<String>>(message: S) -> Self {
Self::BenchmarkExecution {
message: message.into(),
benchmark_name: None,
}
}
pub fn benchmark_execution_with_name<S1: Into<String>, S2: Into<String>>(
name: S1,
message: S2,
) -> Self {
Self::BenchmarkExecution {
message: message.into(),
benchmark_name: Some(name.into()),
}
}
pub fn report_generation<S1: Into<String>, S2: Into<String>>(format: S1, message: S2) -> Self {
Self::ReportGeneration {
format: format.into(),
message: message.into(),
}
}
pub fn baseline<P: Into<PathBuf>, S: Into<String>>(path: P, message: S) -> Self {
Self::Baseline {
path: path.into(),
message: message.into(),
}
}
pub fn scenario_failed<S1: Into<String>, S2: Into<String>>(scenario: S1, message: S2) -> Self {
Self::ScenarioFailed {
scenario: scenario.into(),
message: message.into(),
}
}
pub fn missing_dependency<S1: Into<String>, S2: Into<String>>(
dependency: S1,
feature: S2,
) -> Self {
Self::MissingDependency {
dependency: dependency.into(),
feature: feature.into(),
}
}
pub fn timeout(seconds: u64) -> Self {
Self::Timeout { seconds }
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_error_display() {
let err = BenchError::benchmark_execution("Test failed");
assert!(err.to_string().contains("Test failed"));
let err = BenchError::benchmark_execution_with_name("my_bench", "Test failed");
assert!(err.to_string().contains("Test failed"));
let err = BenchError::report_generation("HTML", "Template error");
assert!(err.to_string().contains("HTML"));
assert!(err.to_string().contains("Template error"));
let err = BenchError::missing_dependency("criterion", "benchmarking");
assert!(err.to_string().contains("criterion"));
assert!(err.to_string().contains("benchmarking"));
let err = BenchError::timeout(30);
assert!(err.to_string().contains("30"));
}
#[test]
fn test_profiler_errors() {
let err = BenchError::profiler_init("Failed to initialize");
assert!(err.to_string().contains("initialization"));
let err = BenchError::profiler_start("Failed to start");
assert!(err.to_string().contains("start"));
let err = BenchError::profiler_stop("Failed to stop");
assert!(err.to_string().contains("stop"));
let err = BenchError::profiler_collect("Failed to collect");
assert!(err.to_string().contains("collection"));
}
#[test]
fn test_scenario_error() {
let err = BenchError::scenario_failed("raster_read", "File not found");
assert!(err.to_string().contains("raster_read"));
assert!(err.to_string().contains("File not found"));
}
#[test]
fn test_baseline_error() {
let err =
BenchError::baseline(std::env::temp_dir().join("baseline.json"), "Corrupted file");
assert!(err.to_string().contains("baseline.json"));
assert!(err.to_string().contains("Corrupted"));
}
}