pub type Source = Box; pub enum Kind { ParseProject, NotAFile(std::path::PathBuf), WriteFile(std::path::PathBuf), RunVampire, InterpretVampireOutput(String, String), } pub struct Error { pub kind: Kind, pub source: Option, } impl Error { pub fn new(kind: Kind) -> Self { Self { kind, source: None, } } pub fn with>(mut self, source: S) -> Self { self.source = Some(source.into()); self } pub fn new_parse_project>(source: S) -> Self { Self::new(Kind::ParseProject).with(source) } pub fn new_not_a_file(path: std::path::PathBuf) -> Self { Self::new(Kind::NotAFile(path)) } pub fn new_write_file>(path: std::path::PathBuf, source: S) -> Self { Self::new(Kind::WriteFile(path)).with(source) } pub fn new_run_vampire>(source: S) -> Self { Self::new(Kind::RunVampire).with(source) } pub fn new_interpret_vampire_output(stdout: String, stderr: String) -> Self { Self::new(Kind::InterpretVampireOutput(stdout, stderr)) } } impl std::fmt::Debug for Error { fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { match self.kind { Kind::ParseProject => write!(formatter, "could not parse project file")?, Kind::NotAFile(ref file_path) => write!(formatter, "specified path is not a file ({})", file_path.display())?, Kind::WriteFile(ref file_path) => write!(formatter, "could not write file ({})", file_path.display())?, Kind::RunVampire => write!(formatter, "could not run Vampire")?, Kind::InterpretVampireOutput(ref stdout, ref stderr) => write!(formatter, "could not interpret Vampire output\n\n======== stdout =========\n{}\n\n======== stderr =========\n{}", stdout, stderr)?, } if let Some(source) = &self.source { write!(formatter, "\nerror source: {}", source)?; } Ok(()) } } impl std::fmt::Display for Error { fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { write!(formatter, "{:?}", self) } } impl std::error::Error for Error { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match &self.source { Some(source) => Some(source.as_ref()), None => None, } } }