use std::fmt;
pub type StatsResult<T> = Result<T, StatsError>;
#[derive(Debug, Clone)]
pub enum StatsError {
InvalidParameter {
name: String,
value: f64,
reason: String,
},
EmptyData { context: String },
InsufficientData {
required: usize,
got: usize,
context: String,
},
InvalidProbability { value: f64 },
OutOfSupport { value: f64, support: String },
NumericalError { message: String },
ConvergenceError { iterations: usize, context: String },
LengthMismatch {
expected: usize,
got: usize,
context: String,
},
}
impl fmt::Display for StatsError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::InvalidParameter {
name,
value,
reason,
} => {
write!(f, "Invalid parameter '{}' = {}: {}", name, value, reason)
}
Self::EmptyData { context } => {
write!(f, "Empty data in {}", context)
}
Self::InsufficientData {
required,
got,
context,
} => {
write!(
f,
"Insufficient data in {}: need {} elements, got {}",
context, required, got
)
}
Self::InvalidProbability { value } => {
write!(f, "Invalid probability {}: must be in [0, 1]", value)
}
Self::OutOfSupport { value, support } => {
write!(f, "Value {} is outside support {}", value, support)
}
Self::NumericalError { message } => {
write!(f, "Numerical error: {}", message)
}
Self::ConvergenceError {
iterations,
context,
} => {
write!(
f,
"{} did not converge after {} iterations",
context, iterations
)
}
Self::LengthMismatch {
expected,
got,
context,
} => {
write!(
f,
"Length mismatch in {}: expected {}, got {}",
context, expected, got
)
}
}
}
}
impl std::error::Error for StatsError {}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_error_display() {
let err = StatsError::InvalidParameter {
name: "sigma".to_string(),
value: -1.0,
reason: "must be positive".to_string(),
};
assert!(err.to_string().contains("sigma"));
assert!(err.to_string().contains("-1"));
let err = StatsError::InvalidProbability { value: 1.5 };
assert!(err.to_string().contains("1.5"));
assert!(err.to_string().contains("[0, 1]"));
}
}