use std::io; use std::path::{Path, PathBuf}; use thiserror::Error; #[derive(Default)] pub struct Errors { errors: Vec, } pub struct Error { location: PathBuf, inner: InnerError, } #[derive(Debug, Error)] pub enum InnerError { #[error("IO Error: {0}")] IoErr(#[from] io::Error), #[error("Failed to parse template file")] TemplateErr(#[from] blueprint::Error), #[error("Failed to parse toml file")] TomlErr(#[from] toml::de::Error), #[error("Unsupported variable type")] TypeErr, } impl From> for Errors { fn from(errors: Vec) -> Self { Errors { errors } } } impl From for Errors where E: Into, { fn from(error: E) -> Self { Errors { errors: vec![error.into()], } } } impl Errors { pub fn join(&mut self, mut other: Errors) { self.errors.append(&mut other.errors); } pub fn is_empty(&self) -> bool { self.errors.is_empty() } pub fn log(self) { if self.errors.is_empty() { return; } error!("{} errors occured:", self.errors.len()); for (i, error) in self.errors.iter().enumerate() { error!(" err {:02} at {:?}:", i, error.location); error!(" {}", error.inner); } } } pub trait ErrorLocation { type Err; fn with_location(self, path: &Path) -> Self::Err; } impl ErrorLocation for T where T: Into, { type Err = Error; fn with_location(self, path: &Path) -> Error { Error { location: path.to_owned(), inner: self.into(), } } } impl ErrorLocation for Result where E: Into, { type Err = Result; fn with_location(self, path: &Path) -> Result { self.map_err(|e| Error { location: path.to_owned(), inner: e.into(), }) } }