error.rs
1 use std::io; 2 use std::path::{Path, PathBuf}; 3 use thiserror::Error; 4 5 #[derive(Default)] 6 pub struct Errors { 7 errors: Vec<Error>, 8 } 9 10 pub struct Error { 11 location: PathBuf, 12 inner: InnerError, 13 } 14 15 #[derive(Debug, Error)] 16 pub enum InnerError { 17 #[error("IO Error: {0}")] 18 IoErr(#[from] io::Error), 19 20 #[error("Failed to parse template file")] 21 TemplateErr(#[from] blueprint::Error), 22 23 #[error("Failed to parse toml file")] 24 TomlErr(#[from] toml::de::Error), 25 26 #[error("Unsupported variable type")] 27 TypeErr, 28 } 29 30 impl From<Vec<Error>> for Errors { 31 fn from(errors: Vec<Error>) -> Self { 32 Errors { errors } 33 } 34 } 35 36 impl<E> From<E> for Errors 37 where 38 E: Into<Error>, 39 { 40 fn from(error: E) -> Self { 41 Errors { 42 errors: vec![error.into()], 43 } 44 } 45 } 46 47 impl Errors { 48 pub fn join(&mut self, mut other: Errors) { 49 self.errors.append(&mut other.errors); 50 } 51 52 pub fn is_empty(&self) -> bool { 53 self.errors.is_empty() 54 } 55 56 pub fn log(self) { 57 if self.errors.is_empty() { 58 return; 59 } 60 61 error!("{} errors occured:", self.errors.len()); 62 for (i, error) in self.errors.iter().enumerate() { 63 error!(" err {:02} at {:?}:", i, error.location); 64 error!(" {}", error.inner); 65 } 66 } 67 } 68 69 pub trait ErrorLocation { 70 type Err; 71 fn with_location(self, path: &Path) -> Self::Err; 72 } 73 74 impl<T> ErrorLocation for T 75 where 76 T: Into<InnerError>, 77 { 78 type Err = Error; 79 80 fn with_location(self, path: &Path) -> Error { 81 Error { 82 location: path.to_owned(), 83 inner: self.into(), 84 } 85 } 86 } 87 88 impl<T, E> ErrorLocation for Result<T, E> 89 where 90 E: Into<InnerError>, 91 { 92 type Err = Result<T, Error>; 93 94 fn with_location(self, path: &Path) -> Result<T, Error> { 95 self.map_err(|e| Error { 96 location: path.to_owned(), 97 inner: e.into(), 98 }) 99 } 100 }