use core::fmt::Display;
use std::convert::Into;
use std::error::Error;
use std::fmt;
use std::io;
#[derive(Debug)]
pub enum Import {
FileExtension(String),
IO(io::Error),
Parse(Parse),
LinearProgram(Inconsistency),
}
impl From<Parse> for Import {
fn from(error: Parse) -> Self {
Self::Parse(error)
}
}
impl From<Inconsistency> for Import {
fn from(error: Inconsistency) -> Self {
Self::LinearProgram(error)
}
}
impl Display for Import {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Import::FileExtension(err) => err.fmt(f),
Import::IO(error) => error.fmt(f),
Import::Parse(error) => error.fmt(f),
Import::LinearProgram(error) => error.fmt(f),
}
}
}
impl Error for Import {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
Import::FileExtension(_) => None,
Import::IO(error) => error.source(),
Import::Parse(error) => error.source(),
Import::LinearProgram(_error) => None,
}
}
}
#[derive(Debug)]
pub struct Parse {
description: String,
source: Option<Source>,
}
pub type ParseResult<T> = Result<T, Parse>;
impl Display for Parse {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f, "ParseError: {}", self.description)
}
}
impl Error for Parse {
fn source(&self) -> Option<&(dyn Error + 'static)> {
if let Some(Source::Other(ref error)) = self.source {
Some(error.as_ref())
} else { None }
}
fn description(&self) -> &str {
self.description.as_str()
}
}
impl Parse {
pub fn new(description: impl Into<String>) -> Self {
Self { description: description.into(), source: None, }
}
pub fn with_location(
description: impl Into<String>,
file_location: FileLocation,
) -> Self {
let (line_number, line) = file_location;
Self {
description: description.into(),
source: Some(Source::FileLocation(line_number, line.to_string())),
}
}
pub fn wrap(self, description: impl Into<String>) -> Self {
Self {
description: description.into(),
source: Some(Source::Parse(Box::new(self))),
}
}
pub fn wrap_other(source: impl Error + 'static, description: impl Into<String>) -> Self {
Self {
description: description.into(),
source: Some(Source::Other(Box::new(source))),
}
}
fn trace(&self) -> Vec<String> {
let mut descriptions = if let Some(ref source) = self.source {
match source {
Source::FileLocation(line_number, line) => {
vec![format!("Caused at line {}: \t{}", line_number, line)]
},
Source::Parse(error) => error.trace(),
Source::Other(error) => vec![error.to_string()],
}
} else {
Vec::new()
};
descriptions.push(self.to_string());
descriptions
}
}
#[derive(Debug)]
enum Source {
FileLocation(usize, String),
Parse(Box<Parse>),
Other(Box<dyn Error>),
}
pub(super) type FileLocation<'a> = (usize, &'a str);
#[derive(Debug, Eq, PartialEq)]
pub struct Inconsistency {
description: String,
}
impl Inconsistency {
pub fn new(description: impl Into<String>) -> Inconsistency {
Inconsistency { description: description.into(), }
}
}
impl Display for Inconsistency {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "ProgramError: {}", self)
}
}
impl Error for Inconsistency {
fn source(&self) -> Option<&(dyn Error + 'static)> {
Some(self)
}
}