pub mod input;
pub mod output;
pub mod schema;
pub mod solvers;
pub mod text;
#[cfg(feature = "python")]
mod python;
pub use schema::*;
#[derive(Debug, thiserror::Error)]
pub enum ParseError {
#[error("log appears empty or truncated")]
Empty,
#[error("log does not look like a {0} log")]
WrongSolver(&'static str),
#[error("{0}")]
Other(String),
}
pub trait LogParser {
fn solver(&self) -> Solver;
fn sniff(&self, text: &str) -> bool;
fn parse(&self, text: &str) -> Result<SolverLog, ParseError>;
}
pub fn parse(text: &str, solver: Solver) -> Result<SolverLog, ParseError> {
if text.trim().is_empty() {
return Err(ParseError::Empty);
}
match solver {
Solver::Gurobi => solvers::gurobi::GurobiParser.parse(text),
Solver::Xpress => solvers::xpress::XpressParser.parse(text),
Solver::Scip => solvers::scip::ScipParser.parse(text),
Solver::Highs => solvers::highs::HighsParser.parse(text),
Solver::Cplex => solvers::cplex::CplexParser.parse(text),
Solver::Cbc => solvers::cbc::CbcParser.parse(text),
Solver::Copt => solvers::copt::CoptParser.parse(text),
Solver::Optverse => solvers::optverse::OptverseParser.parse(text),
Solver::Mosek => solvers::mosek::MosekParser.parse(text),
}
}
pub fn autodetect(text: &str) -> Result<SolverLog, ParseError> {
if text.trim().is_empty() {
return Err(ParseError::Empty);
}
let candidates: &[&dyn LogParser] = &[
&solvers::gurobi::GurobiParser,
&solvers::xpress::XpressParser,
&solvers::scip::ScipParser,
&solvers::highs::HighsParser,
&solvers::cplex::CplexParser,
&solvers::cbc::CbcParser,
&solvers::copt::CoptParser,
&solvers::optverse::OptverseParser,
&solvers::mosek::MosekParser,
];
for p in candidates {
if p.sniff(text) {
return p.parse(text);
}
}
Err(ParseError::Other("no parser recognized the log".into()))
}