1use crate::diagnostics::Diagnostic;
6use std::fmt::{Debug, Display};
7use tracing::error;
8
9#[derive(Debug)]
17pub enum Error {
18 IoError {
20 source: std::io::Error,
21 },
22 Utf8Error {
24 source: core::str::Utf8Error,
25 },
26 FromUtf8Error {
28 source: std::string::FromUtf8Error,
29 },
30 UrlParseError {
33 source: Option<url::ParseError>,
34 },
35 TracingFilterError {
37 source: tracing_subscriber::filter::ParseError,
38 },
39 TracingSubscriberError {
41 source: tracing::subscriber::SetGlobalDefaultError,
42 },
43 CodespanReportingError {
44 source: codespan_reporting::files::Error,
45 },
46 LanguageValidationError {
48 source: Diagnostic,
49 },
50 LanguageTagError {
51 source: language_tags::ParseError,
52 },
53 #[cfg(feature = "templates")]
54 Template {
55 source: tera::Error,
56 },
57 GeneratorError {
58 name: String,
59 message: String,
60 },
61}
62
63pub type Result<T> = std::result::Result<T, Error>;
67
68macro_rules! report_and_return {
73 ($err: expr) => {
74 let err = $err;
75 error!("{}", err);
76 return err;
77 };
78}
79
80impl Display for Error {
85 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
86 write!(
87 f,
88 "{}",
89 match self {
90 Self::IoError { source } => format!("An I/O error occurred; source: {source}"),
91 Self::Utf8Error { source } =>
92 format!("A UTF-8 conversion error occurred; source: {source}"),
93 Self::FromUtf8Error { source } =>
94 format!("A UTF-8 conversion error occurred; source: {source}"),
95 Self::UrlParseError { source } =>
96 if let Some(source) = source {
97 format!("An error occurred parsing a URL; source: {source}")
98 } else {
99 "An error occurred creating a URL from a file path".to_string()
100 },
101 Self::TracingFilterError { source } =>
102 format!("A error occurred parsing a tracing filter; source: {source}"),
103 Self::TracingSubscriberError { source } =>
104 format!("A error occurred setting the tracing subscriber; source: {source}"),
105 Self::CodespanReportingError { source } =>
106 format!("An error occurred formatting codespan reports; source: {source}"),
107 Self::LanguageValidationError { source } =>
108 format!("Validation diagnostic: {}", source.message),
109 Self::LanguageTagError { source } =>
110 format!("An error occurred parsing a BCP-47 language tag; source: {source}"),
111 Self::GeneratorError { name, message } =>
112 format!("An error occurred in a generator named `{name}`: {message}"),
113 #[cfg(feature = "templates")]
114 Self::Template { source } =>
115 format!("An error occurred in the template generator; source: {source}"),
116 }
117 )
118 }
119}
120
121impl std::error::Error for Error {
122 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
123 #[allow(unreachable_patterns)]
124 match self {
125 Error::IoError { source } => Some(source),
126 Error::Utf8Error { source } => Some(source),
127 Self::FromUtf8Error { source } => Some(source),
128 Self::TracingFilterError { source } => Some(source),
129 Self::TracingSubscriberError { source } => Some(source),
130 Self::CodespanReportingError { source } => Some(source),
131 #[cfg(feature = "templates")]
132 Self::Template { source } => Some(source),
133 _ => None,
134 }
135 }
136}
137
138impl<T> From<Error> for Result<T> {
139 fn from(value: Error) -> Self {
140 Err(value)
141 }
142}
143
144impl From<std::io::Error> for Error {
145 fn from(source: std::io::Error) -> Self {
146 report_and_return! {
147 Error::IoError { source }
148 }
149 }
150}
151
152impl From<core::str::Utf8Error> for Error {
153 fn from(source: core::str::Utf8Error) -> Self {
154 report_and_return! {
155 Error::Utf8Error { source }
156 }
157 }
158}
159
160impl From<std::string::FromUtf8Error> for Error {
161 fn from(source: std::string::FromUtf8Error) -> Self {
162 report_and_return! {
163 Error::FromUtf8Error { source }
164 }
165 }
166}
167
168impl From<url::ParseError> for Error {
169 fn from(source: url::ParseError) -> Self {
170 report_and_return! {
171 Error::UrlParseError { source: Some(source) }
172 }
173 }
174}
175
176impl From<tracing_subscriber::filter::ParseError> for Error {
177 fn from(source: tracing_subscriber::filter::ParseError) -> Self {
178 report_and_return! {
179 Error::TracingFilterError { source }
180 }
181 }
182}
183
184impl From<tracing::subscriber::SetGlobalDefaultError> for Error {
185 fn from(source: tracing::subscriber::SetGlobalDefaultError) -> Self {
186 report_and_return! {
187 Error::TracingSubscriberError { source }
188 }
189 }
190}
191
192impl From<codespan_reporting::files::Error> for Error {
193 fn from(source: codespan_reporting::files::Error) -> Self {
194 report_and_return! {
195 Error::CodespanReportingError { source }
196 }
197 }
198}
199
200impl From<language_tags::ParseError> for Error {
201 fn from(source: language_tags::ParseError) -> Self {
202 report_and_return! {
203 Error::LanguageTagError { source }
204 }
205 }
206}
207
208impl From<Diagnostic> for Error {
209 fn from(source: Diagnostic) -> Self {
210 report_and_return! {
211 Self::LanguageValidationError { source }
212 }
213 }
214}
215
216#[cfg(feature = "templates")]
217impl From<tera::Error> for Error {
218 fn from(source: tera::Error) -> Self {
219 report_and_return! {
220 Self::Template { source }
221 }
222 }
223}