use crate::intern::Sym;
use thiserror::Error;
pub type Result<T> = core::result::Result<T, Error>;
#[derive(Debug, Clone)]
pub struct OptimizationDetails {
pub score: f64,
pub iterations: u32,
pub threshold: f64,
pub feedback: Option<String>,
pub convergence_failure: bool,
}
impl OptimizationDetails {
pub fn new(score: f64, iterations: u32, threshold: f64) -> Self {
Self {
score,
iterations,
threshold,
feedback: None,
convergence_failure: true,
}
}
pub fn with_feedback(mut self, feedback: impl Into<String>) -> Self {
self.feedback = Some(feedback.into());
self
}
pub fn max_iterations_reached(mut self) -> Self {
self.convergence_failure = false;
self
}
pub fn made_progress(&self) -> bool {
self.score > 0.0 && self.iterations > 0
}
pub fn score_gap(&self) -> f64 {
self.threshold - self.score
}
}
impl core::fmt::Display for OptimizationDetails {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(
f,
"score={:.2} (threshold={:.2}), iterations={}",
self.score, self.threshold, self.iterations
)?;
if let Some(ref fb) = self.feedback {
write!(f, ", feedback: {}", fb)?;
}
Ok(())
}
}
#[derive(Error, Debug)]
pub enum Error {
#[error("Signature error: {0}")]
Signature(String),
#[error("Field error: {0}")]
Field(String),
#[error("Module error: {0}")]
Module(String),
#[error("Prediction error: {0}")]
Prediction(String),
#[error("Serialization error: {0}")]
Serialization(String),
#[error("Assertion failed for field {field:?}: {description}")]
AssertionFailed {
field: Sym,
description: &'static str,
},
#[error("Invalid pattern: {0}")]
InvalidPattern(String),
#[cfg(feature = "std")]
#[error("I/O error: {0}")]
Io(#[from] std::io::Error),
#[error("JSON error: {0}")]
Json(#[from] serde_json::Error),
#[error("UTF-8 error: {0}")]
Utf8(#[from] std::str::Utf8Error),
#[error("Storage error: {0}")]
Storage(String),
#[error("Memory error: {operation} failed — {reason}. {suggestion}")]
Memory {
operation: &'static str,
reason: String,
suggestion: &'static str,
},
#[error("Parse error: {0}")]
Parse(String),
#[error("Validation error: {0}")]
Validation(String),
#[error("Optimization failed: {0}")]
Optimization(OptimizationDetails),
#[error("{0}")]
Other(String),
}
impl Error {
pub fn storage(msg: impl Into<String>) -> Self {
Self::Storage(msg.into())
}
pub fn memory(
operation: &'static str,
reason: impl Into<String>,
suggestion: &'static str,
) -> Self {
Self::Memory {
operation,
reason: reason.into(),
suggestion,
}
}
pub fn signature(msg: impl Into<String>) -> Self {
Self::Signature(msg.into())
}
pub fn field(msg: impl Into<String>) -> Self {
Self::Field(msg.into())
}
pub fn module(msg: impl Into<String>) -> Self {
Self::Module(msg.into())
}
pub fn prediction(msg: impl Into<String>) -> Self {
Self::Prediction(msg.into())
}
pub fn parse(msg: impl Into<String>) -> Self {
Self::Parse(msg.into())
}
pub fn validation(msg: impl Into<String>) -> Self {
Self::Validation(msg.into())
}
#[cfg(feature = "std")]
pub fn io(msg: impl Into<String>) -> Self {
Self::Other(msg.into())
}
pub fn optimization(score: f64, iterations: u32, threshold: f64) -> Self {
Self::Optimization(OptimizationDetails::new(score, iterations, threshold))
}
pub fn optimization_with_feedback(
score: f64,
iterations: u32,
threshold: f64,
feedback: impl Into<String>,
) -> Self {
Self::Optimization(
OptimizationDetails::new(score, iterations, threshold).with_feedback(feedback),
)
}
#[inline]
pub fn is_optimization_error(&self) -> bool {
matches!(self, Self::Optimization(_))
}
#[inline]
pub fn is_library_error(&self) -> bool {
!self.is_optimization_error()
}
#[inline]
pub fn optimization_details(&self) -> Option<&OptimizationDetails> {
match self {
Self::Optimization(details) => Some(details),
_ => None,
}
}
#[inline]
pub fn optimization_details_mut(&mut self) -> Option<&mut OptimizationDetails> {
match self {
Self::Optimization(details) => Some(details),
_ => None,
}
}
#[inline]
pub fn is_recoverable(&self) -> bool {
self.is_optimization_error()
}
pub fn category(&self) -> &'static str {
match self {
Self::Signature(_) => "signature",
Self::Field(_) => "field",
Self::Module(_) => "module",
Self::Prediction(_) => "prediction",
Self::Serialization(_) => "serialization",
Self::AssertionFailed { .. } => "assertion",
Self::InvalidPattern(_) => "pattern",
#[cfg(feature = "std")]
Self::Io(_) => "io",
Self::Json(_) => "json",
Self::Utf8(_) => "utf8",
Self::Storage(_) => "storage",
Self::Memory { .. } => "memory",
Self::Parse(_) => "parse",
Self::Validation(_) => "validation",
Self::Optimization(_) => "optimization",
Self::Other(_) => "other",
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_error_signature() {
let err = Error::signature("invalid format");
assert!(matches!(err, Error::Signature(_)));
assert_eq!(err.to_string(), "Signature error: invalid format");
}
#[test]
fn test_error_field() {
let err = Error::field("missing field");
assert!(matches!(err, Error::Field(_)));
assert_eq!(err.to_string(), "Field error: missing field");
}
#[test]
fn test_error_module() {
let err = Error::module("execution failed");
assert!(matches!(err, Error::Module(_)));
assert_eq!(err.to_string(), "Module error: execution failed");
}
#[test]
fn test_error_prediction() {
let err = Error::prediction("parsing failed");
assert!(matches!(err, Error::Prediction(_)));
assert_eq!(err.to_string(), "Prediction error: parsing failed");
}
#[test]
fn test_result_type() {
let ok: Result<i32> = Ok(42);
assert!(ok.is_ok());
let err: Result<i32> = Err(Error::Other("failed".to_string()));
assert!(err.is_err());
}
#[test]
fn test_optimization_error_creation() {
let err = Error::optimization(0.75, 5, 0.9);
assert!(err.is_optimization_error());
assert!(!err.is_library_error());
assert!(err.is_recoverable());
let details = err.optimization_details().unwrap();
assert!((details.score - 0.75).abs() < 0.001);
assert_eq!(details.iterations, 5);
assert!((details.threshold - 0.9).abs() < 0.001);
}
#[test]
fn test_optimization_error_with_feedback() {
let err = Error::optimization_with_feedback(0.6, 3, 0.8, "Missing return type annotation");
let details = err.optimization_details().unwrap();
assert_eq!(
details.feedback.as_deref(),
Some("Missing return type annotation")
);
}
#[test]
fn test_optimization_details_methods() {
let details = OptimizationDetails::new(0.7, 4, 0.9)
.with_feedback("Test feedback")
.max_iterations_reached();
assert!((details.score_gap() - 0.2).abs() < 0.001);
assert!(details.made_progress());
assert!(!details.convergence_failure);
}
#[test]
fn test_optimization_details_display() {
let details = OptimizationDetails::new(0.75, 5, 0.9).with_feedback("Needs docstring");
let display = details.to_string();
assert!(display.contains("0.75"));
assert!(display.contains("0.9"));
assert!(display.contains("5"));
assert!(display.contains("Needs docstring"));
}
#[test]
fn test_is_library_error() {
assert!(Error::signature("bad").is_library_error());
assert!(Error::field("bad").is_library_error());
assert!(Error::module("bad").is_library_error());
assert!(Error::parse("bad").is_library_error());
assert!(!Error::optimization(0.5, 3, 0.9).is_library_error());
}
#[test]
fn test_error_category() {
assert_eq!(Error::signature("x").category(), "signature");
assert_eq!(Error::field("x").category(), "field");
assert_eq!(Error::module("x").category(), "module");
assert_eq!(Error::prediction("x").category(), "prediction");
assert_eq!(Error::parse("x").category(), "parse");
assert_eq!(Error::validation("x").category(), "validation");
assert_eq!(Error::optimization(0.5, 1, 0.9).category(), "optimization");
assert_eq!(Error::Other("x".to_string()).category(), "other");
}
#[test]
fn test_optimization_error_message() {
let err = Error::optimization_with_feedback(0.65, 10, 0.9, "Missing tests");
let msg = err.to_string();
assert!(msg.contains("Optimization failed"));
assert!(msg.contains("0.65"));
}
#[test]
fn test_mutable_optimization_details() {
let mut err = Error::optimization(0.5, 2, 0.9);
if let Some(details) = err.optimization_details_mut() {
details.feedback = Some("Updated feedback".to_string());
}
let details = err.optimization_details().unwrap();
assert_eq!(details.feedback.as_deref(), Some("Updated feedback"));
}
}