use std::ffi::{CStr, NulError};
use std::fmt;
use crate::symbol::Symbol;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ClingoErrorCode {
Runtime,
Logic,
BadAlloc,
Unknown,
}
#[derive(Debug, Clone)]
pub struct ClingoError {
pub code: ClingoErrorCode,
pub message: Option<String>,
}
impl fmt::Display for ClingoError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self.message {
Some(msg) => write!(f, "clingo {:?}: {}", self.code, msg),
None => write!(f, "clingo {:?}", self.code),
}
}
}
impl std::error::Error for ClingoError {}
#[derive(Debug)]
pub enum Error {
Clingo(ClingoError),
NulByte(NulError),
TypeMismatch(String),
}
impl Error {
pub(crate) fn type_mismatch(symbol: Symbol) -> Error {
Error::TypeMismatch(format!(
"atom {} does not match expected argument types",
symbol.to_string_lossy().unwrap_or_else(|_| "?".into()),
))
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Error::Clingo(e) => e.fmt(f),
Error::NulByte(e) => e.fmt(f),
Error::TypeMismatch(msg) => write!(f, "type mismatch: {}", msg),
}
}
}
impl std::error::Error for Error {}
impl From<NulError> for Error {
fn from(e: NulError) -> Self {
Error::NulByte(e)
}
}
impl From<ClingoError> for Error {
fn from(e: ClingoError) -> Self {
Error::Clingo(e)
}
}
fn last_clingo_error() -> ClingoError {
unsafe {
let code = clingo_sys::clingo_error_code();
let msg_ptr = clingo_sys::clingo_error_message();
let message = if msg_ptr.is_null() {
None
} else {
Some(CStr::from_ptr(msg_ptr).to_string_lossy().into_owned())
};
let code = match code as u32 {
clingo_sys::clingo_error_e_clingo_error_runtime => ClingoErrorCode::Runtime,
clingo_sys::clingo_error_e_clingo_error_logic => ClingoErrorCode::Logic,
clingo_sys::clingo_error_e_clingo_error_bad_alloc => ClingoErrorCode::BadAlloc,
_ => ClingoErrorCode::Unknown,
};
ClingoError { code, message }
}
}
pub(crate) fn check(ok: bool) -> Result<(), ClingoError> {
if ok { Ok(()) } else { Err(last_clingo_error()) }
}