gazetta_core/
error.rs

1//  Copyright (C) 2015 Steven Allen
2//
3//  This file is part of gazetta.
4//
5//  This program is free software: you can redistribute it and/or modify it under the terms of the
6//  GNU General Public License as published by the Free Software Foundation version 3 of the
7//  License.
8//
9//  This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
10//  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
11//  the GNU General Public License for more details.
12//
13//  You should have received a copy of the GNU General Public License along with this program.  If
14//  not, see <http://www.gnu.org/licenses/>.
15//
16
17use std::borrow::Cow;
18use std::fmt;
19use std::io;
20use std::path::PathBuf;
21
22use glob::PatternError;
23use horrorshow;
24
25use crate::model::index::SortError;
26use crate::yaml::ScanError;
27
28use std::error::Error;
29
30macro_rules! try_annotate {
31    ($e:expr, $l:expr) => {
32        match $e {
33            Ok(v) => v,
34            Err(e) => {
35                return Err($crate::error::AnnotatedError::new(
36                    ($l).to_owned(),
37                    From::from(e),
38                ));
39            }
40        }
41    };
42}
43
44#[derive(Debug)]
45pub enum SourceError {
46    Parse(ScanError),
47    Read(io::Error),
48    Config(Cow<'static, str>),
49}
50
51impl Error for SourceError {
52    fn description(&self) -> &str {
53        use self::SourceError::*;
54        match *self {
55            Parse(..) => "yaml parse error",
56            Read(..) => "read error",
57            Config(..) => "config error",
58        }
59    }
60    fn source(&self) -> Option<&(dyn Error + 'static)> {
61        use self::SourceError::*;
62        match *self {
63            Read(ref e) => Some(e),
64            // Parse(ref e) => e, // TODO: wait for upstream
65            _ => None,
66        }
67    }
68}
69
70impl fmt::Display for SourceError {
71    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
72        use self::SourceError::*;
73        match *self {
74            Parse(ref e) => write!(f, "yaml parse error '{:?}'", e),
75            Read(ref e) => write!(f, "read error '{}'", e),
76            Config(ref e) => write!(f, "config error '{}'", e),
77        }
78    }
79}
80
81#[derive(Debug, Clone)]
82pub struct AnnotatedError<E>
83where
84    E: Error + 'static,
85{
86    pub location: PathBuf,
87    pub error: E,
88}
89
90// Would like to make this generic but coherence...
91impl From<AnnotatedError<io::Error>> for AnnotatedError<RenderError> {
92    fn from(e: AnnotatedError<io::Error>) -> AnnotatedError<RenderError> {
93        AnnotatedError {
94            location: e.location,
95            error: From::from(e.error),
96        }
97    }
98}
99
100impl<E> Error for AnnotatedError<E>
101where
102    E: Error + 'static,
103{
104    fn description(&self) -> &str {
105        #[allow(deprecated)]
106        self.error.description()
107    }
108    fn source(&self) -> Option<&(dyn Error + 'static)> {
109        Some(&self.error)
110    }
111}
112
113impl<E> fmt::Display for AnnotatedError<E>
114where
115    E: Error,
116{
117    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
118        write!(
119            f,
120            "when processing {}: {}",
121            self.location.display(),
122            self.error
123        )
124    }
125}
126
127impl<E> AnnotatedError<E>
128where
129    E: Error,
130{
131    pub fn new(location: PathBuf, error: E) -> AnnotatedError<E> {
132        AnnotatedError { location, error }
133    }
134}
135
136impl From<io::Error> for SourceError {
137    fn from(e: io::Error) -> SourceError {
138        SourceError::Read(e)
139    }
140}
141
142impl From<::url::ParseError> for SourceError {
143    fn from(e: ::url::ParseError) -> SourceError {
144        SourceError::Config(Cow::Owned(format!("{}", e)))
145    }
146}
147
148impl From<ScanError> for SourceError {
149    fn from(e: ScanError) -> SourceError {
150        SourceError::Parse(e)
151    }
152}
153
154impl From<PatternError> for SourceError {
155    fn from(_: PatternError) -> SourceError {
156        SourceError::from("invalid index directory pattern")
157    }
158}
159
160impl From<&'static str> for SourceError {
161    fn from(e: &'static str) -> SourceError {
162        SourceError::Config(Cow::Borrowed(e))
163    }
164}
165
166impl From<String> for SourceError {
167    fn from(e: String) -> SourceError {
168        SourceError::Config(Cow::Owned(e))
169    }
170}
171
172impl From<SortError> for SourceError {
173    fn from(value: SortError) -> Self {
174        value.to_string().into()
175    }
176}
177
178pub type RenderError = horrorshow::Error;