use crate::types::Index;
use std::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[allow(non_camel_case_types)]
pub enum ExceptionKind {
OPTION_INVALID,
OPTION_ALREADY_REGISTERED,
DYNAMIC_LIBRARY_FAILURE,
UNIMPLEMENTED_LINALG_METHOD_CALLED,
UNKNOWN_MATRIX_TYPE,
UNKNOWN_VECTOR_TYPE,
LAPACK_NOT_INCLUDED,
METADATA_ERROR,
TINY_STEP_DETECTED,
ACCEPTABLE_POINT_REACHED,
STEP_COMPUTATION_FAILED,
LOCALLY_INFEASIBLE,
FEASIBILITY_PROBLEM_SOLVED,
RESTORATION_FAILED,
RESTORATION_CONVERGED_TO_FEASIBLE_POINT,
RESTORATION_MAXITER_EXCEEDED,
RESTORATION_CPUTIME_EXCEEDED,
RESTORATION_WALLTIME_EXCEEDED,
RESTORATION_USER_STOP,
FATAL_ERROR_IN_LINEAR_SOLVER,
ERROR_IN_LINEAR_SCALING_METHOD,
NONPOSITIVE_SCALING_FACTOR,
USER_SCALING_NOT_IMPLEMENTED,
INVALID_NLP,
INVALID_TNLP,
INVALID_STDINTERFACE_NLP,
INVALID_WARMSTART,
INCONSISTENT_BOUNDS,
TOO_FEW_DOF,
ERROR_IN_TNLP_DERIVATIVE_TEST,
IPOPT_APPLICATION_ERROR,
FAILED_INITIALIZATION,
INTERNAL_ABORT,
ERROR_CONVERTING_STRING_TO_ENUM,
}
impl ExceptionKind {
pub fn name(self) -> &'static str {
use ExceptionKind::*;
match self {
OPTION_INVALID => "OPTION_INVALID",
OPTION_ALREADY_REGISTERED => "OPTION_ALREADY_REGISTERED",
DYNAMIC_LIBRARY_FAILURE => "DYNAMIC_LIBRARY_FAILURE",
UNIMPLEMENTED_LINALG_METHOD_CALLED => "UNIMPLEMENTED_LINALG_METHOD_CALLED",
UNKNOWN_MATRIX_TYPE => "UNKNOWN_MATRIX_TYPE",
UNKNOWN_VECTOR_TYPE => "UNKNOWN_VECTOR_TYPE",
LAPACK_NOT_INCLUDED => "LAPACK_NOT_INCLUDED",
METADATA_ERROR => "METADATA_ERROR",
TINY_STEP_DETECTED => "TINY_STEP_DETECTED",
ACCEPTABLE_POINT_REACHED => "ACCEPTABLE_POINT_REACHED",
STEP_COMPUTATION_FAILED => "STEP_COMPUTATION_FAILED",
LOCALLY_INFEASIBLE => "LOCALLY_INFEASIBLE",
FEASIBILITY_PROBLEM_SOLVED => "FEASIBILITY_PROBLEM_SOLVED",
RESTORATION_FAILED => "RESTORATION_FAILED",
RESTORATION_CONVERGED_TO_FEASIBLE_POINT => "RESTORATION_CONVERGED_TO_FEASIBLE_POINT",
RESTORATION_MAXITER_EXCEEDED => "RESTORATION_MAXITER_EXCEEDED",
RESTORATION_CPUTIME_EXCEEDED => "RESTORATION_CPUTIME_EXCEEDED",
RESTORATION_WALLTIME_EXCEEDED => "RESTORATION_WALLTIME_EXCEEDED",
RESTORATION_USER_STOP => "RESTORATION_USER_STOP",
FATAL_ERROR_IN_LINEAR_SOLVER => "FATAL_ERROR_IN_LINEAR_SOLVER",
ERROR_IN_LINEAR_SCALING_METHOD => "ERROR_IN_LINEAR_SCALING_METHOD",
NONPOSITIVE_SCALING_FACTOR => "NONPOSITIVE_SCALING_FACTOR",
USER_SCALING_NOT_IMPLEMENTED => "USER_SCALING_NOT_IMPLEMENTED",
INVALID_NLP => "INVALID_NLP",
INVALID_TNLP => "INVALID_TNLP",
INVALID_STDINTERFACE_NLP => "INVALID_STDINTERFACE_NLP",
INVALID_WARMSTART => "INVALID_WARMSTART",
INCONSISTENT_BOUNDS => "INCONSISTENT_BOUNDS",
TOO_FEW_DOF => "TOO_FEW_DOF",
ERROR_IN_TNLP_DERIVATIVE_TEST => "ERROR_IN_TNLP_DERIVATIVE_TEST",
IPOPT_APPLICATION_ERROR => "IPOPT_APPLICATION_ERROR",
FAILED_INITIALIZATION => "FAILED_INITIALIZATION",
INTERNAL_ABORT => "INTERNAL_ABORT",
ERROR_CONVERTING_STRING_TO_ENUM => "ERROR_CONVERTING_STRING_TO_ENUM",
}
}
}
impl fmt::Display for ExceptionKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.name())
}
}
#[derive(Debug, Clone)]
pub struct SolverException {
pub kind: ExceptionKind,
pub message: String,
pub file: &'static str,
pub line: Index,
}
impl SolverException {
pub fn new(
kind: ExceptionKind,
message: impl Into<String>,
file: &'static str,
line: Index,
) -> Self {
Self {
kind,
message: message.into(),
file,
line,
}
}
}
impl fmt::Display for SolverException {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"Exception of type: {} in file \"{}\" at line {}:\n Exception message: {}",
self.kind, self.file, self.line, self.message
)
}
}
impl std::error::Error for SolverException {}
#[macro_export]
macro_rules! throw {
($kind:expr, $msg:expr) => {
return ::core::result::Result::Err($crate::exception::SolverException::new(
$kind,
$msg,
file!(),
line!() as $crate::types::Index,
))
};
}
#[macro_export]
macro_rules! assert_exc {
($cond:expr, $kind:expr, $msg:expr) => {
if !($cond) {
let mut newmsg = ::std::string::String::from(stringify!($cond));
newmsg.push_str(" evaluated false: ");
newmsg.push_str($msg);
return ::core::result::Result::Err($crate::exception::SolverException::new(
$kind,
newmsg,
file!(),
line!() as $crate::types::Index,
));
}
};
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn display_matches_upstream_format() {
let e = SolverException::new(
ExceptionKind::OPTION_INVALID,
"bad option",
"src/foo.rs",
42,
);
let s = format!("{}", e);
assert!(s.contains("Exception of type: OPTION_INVALID"));
assert!(s.contains("src/foo.rs"));
assert!(s.contains("line 42"));
assert!(s.contains("Exception message: bad option"));
}
#[test]
fn names_all_round_trip() {
for k in [
ExceptionKind::OPTION_INVALID,
ExceptionKind::TINY_STEP_DETECTED,
ExceptionKind::RESTORATION_FAILED,
ExceptionKind::LOCALLY_INFEASIBLE,
] {
assert!(!k.name().is_empty());
assert_eq!(format!("{k}"), k.name());
}
}
}