use crate::diagnostics::Diagnostic;
use std::fmt::{Debug, Display};
use tracing::error;
#[derive(Debug)]
pub enum Error {
IoError {
source: std::io::Error,
},
Utf8Error {
source: core::str::Utf8Error,
},
FromUtf8Error {
source: std::string::FromUtf8Error,
},
UrlParseError {
source: Option<url::ParseError>,
},
TracingFilterError {
source: tracing_subscriber::filter::ParseError,
},
TracingSubscriberError {
source: tracing::subscriber::SetGlobalDefaultError,
},
CodespanReportingError {
source: codespan_reporting::files::Error,
},
LanguageValidationError {
source: Diagnostic,
},
LanguageTagError {
source: language_tags::ParseError,
},
#[cfg(feature = "templates")]
Template {
source: tera::Error,
},
GeneratorError {
name: String,
message: String,
},
}
pub type Result<T> = std::result::Result<T, Error>;
macro_rules! report_and_return {
($err: expr) => {
let err = $err;
error!("{}", err);
return err;
};
}
impl Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
Self::IoError { source } => format!("An I/O error occurred; source: {source}"),
Self::Utf8Error { source } =>
format!("A UTF-8 conversion error occurred; source: {source}"),
Self::FromUtf8Error { source } =>
format!("A UTF-8 conversion error occurred; source: {source}"),
Self::UrlParseError { source } =>
if let Some(source) = source {
format!("An error occurred parsing a URL; source: {source}")
} else {
"An error occurred creating a URL from a file path".to_string()
},
Self::TracingFilterError { source } =>
format!("A error occurred parsing a tracing filter; source: {source}"),
Self::TracingSubscriberError { source } =>
format!("A error occurred setting the tracing subscriber; source: {source}"),
Self::CodespanReportingError { source } =>
format!("An error occurred formatting codespan reports; source: {source}"),
Self::LanguageValidationError { source } =>
format!("Validation diagnostic: {}", source.message),
Self::LanguageTagError { source } =>
format!("An error occurred parsing a BCP-47 language tag; source: {source}"),
Self::GeneratorError { name, message } =>
format!("An error occurred in a generator named `{name}`: {message}"),
#[cfg(feature = "templates")]
Self::Template { source } =>
format!("An error occurred in the template generator; source: {source}"),
}
)
}
}
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
#[allow(unreachable_patterns)]
match self {
Error::IoError { source } => Some(source),
Error::Utf8Error { source } => Some(source),
Self::FromUtf8Error { source } => Some(source),
Self::TracingFilterError { source } => Some(source),
Self::TracingSubscriberError { source } => Some(source),
Self::CodespanReportingError { source } => Some(source),
#[cfg(feature = "templates")]
Self::Template { source } => Some(source),
_ => None,
}
}
}
impl<T> From<Error> for Result<T> {
fn from(value: Error) -> Self {
Err(value)
}
}
impl From<std::io::Error> for Error {
fn from(source: std::io::Error) -> Self {
report_and_return! {
Error::IoError { source }
}
}
}
impl From<core::str::Utf8Error> for Error {
fn from(source: core::str::Utf8Error) -> Self {
report_and_return! {
Error::Utf8Error { source }
}
}
}
impl From<std::string::FromUtf8Error> for Error {
fn from(source: std::string::FromUtf8Error) -> Self {
report_and_return! {
Error::FromUtf8Error { source }
}
}
}
impl From<url::ParseError> for Error {
fn from(source: url::ParseError) -> Self {
report_and_return! {
Error::UrlParseError { source: Some(source) }
}
}
}
impl From<tracing_subscriber::filter::ParseError> for Error {
fn from(source: tracing_subscriber::filter::ParseError) -> Self {
report_and_return! {
Error::TracingFilterError { source }
}
}
}
impl From<tracing::subscriber::SetGlobalDefaultError> for Error {
fn from(source: tracing::subscriber::SetGlobalDefaultError) -> Self {
report_and_return! {
Error::TracingSubscriberError { source }
}
}
}
impl From<codespan_reporting::files::Error> for Error {
fn from(source: codespan_reporting::files::Error) -> Self {
report_and_return! {
Error::CodespanReportingError { source }
}
}
}
impl From<language_tags::ParseError> for Error {
fn from(source: language_tags::ParseError) -> Self {
report_and_return! {
Error::LanguageTagError { source }
}
}
}
impl From<Diagnostic> for Error {
fn from(source: Diagnostic) -> Self {
report_and_return! {
Self::LanguageValidationError { source }
}
}
}
#[cfg(feature = "templates")]
impl From<tera::Error> for Error {
fn from(source: tera::Error) -> Self {
report_and_return! {
Self::Template { source }
}
}
}