use crate::{cache::CacheError, html_parser::HtmlParseError, http_client::HttpClientError};
use core::{
error,
fmt::{self, Display, Formatter},
str::Utf8Error,
};
use http::StatusCode;
use serde::{Serialize, Serializer};
use std::io;
use tokio::{sync::AcquireError, task::JoinError};
use url::ParseError;
#[derive(Debug)]
pub enum Error {
Acquire(AcquireError),
Cache(CacheError),
HtmlParse(HtmlParseError),
Io(io::Error),
Item(ItemError),
Join(JoinError),
Json(serde_json::Error),
Sitemap(sitemaps::error::Error),
Sled(sled::Error),
UrlParse(ParseError),
Utf8(Utf8Error),
Validation,
}
impl error::Error for Error {}
impl Display for Error {
fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
match self {
Self::Acquire(error) => write!(formatter, "{error}"),
Self::Cache(error) => write!(formatter, "{error}"),
Self::HtmlParse(error) => write!(formatter, "{error}"),
Self::Io(error) => write!(formatter, "{error}"),
Self::Item(error) => write!(formatter, "{error}"),
Self::Join(error) => write!(formatter, "{error}"),
Self::Json(error) => write!(formatter, "{error}"),
Self::Sitemap(error) => write!(formatter, "{error}"),
Self::Sled(error) => write!(formatter, "{error}"),
Self::UrlParse(error) => write!(formatter, "{error}"),
Self::Utf8(error) => write!(formatter, "{error}"),
Self::Validation => write!(formatter, "validation failed"),
}
}
}
impl From<ItemError> for Error {
fn from(error: ItemError) -> Self {
Self::Item(error)
}
}
impl From<AcquireError> for Error {
fn from(error: AcquireError) -> Self {
Self::Acquire(error)
}
}
impl From<CacheError> for Error {
fn from(error: CacheError) -> Self {
Self::Cache(error)
}
}
impl From<io::Error> for Error {
fn from(error: io::Error) -> Self {
Self::Io(error)
}
}
impl From<HtmlParseError> for Error {
fn from(error: HtmlParseError) -> Self {
Self::HtmlParse(error)
}
}
impl From<JoinError> for Error {
fn from(error: JoinError) -> Self {
Self::Join(error)
}
}
impl From<serde_json::Error> for Error {
fn from(error: serde_json::Error) -> Self {
Self::Json(error)
}
}
impl From<sled::Error> for Error {
fn from(error: sled::Error) -> Self {
Self::Sled(error)
}
}
impl From<url::ParseError> for Error {
fn from(error: url::ParseError) -> Self {
Self::UrlParse(error)
}
}
impl From<sitemaps::error::Error> for Error {
fn from(error: sitemaps::error::Error) -> Self {
Self::Sitemap(error)
}
}
impl From<Utf8Error> for Error {
fn from(error: Utf8Error) -> Self {
Self::Utf8(error)
}
}
#[derive(Debug)]
pub enum ItemError {
ContentTypeInvalid {
actual: String,
expected: &'static str,
},
HtmlElementNotFound(String),
HtmlParse(HtmlParseError),
HtmlValidation(muffy_validation::MarkupError),
HttpClient(HttpClientError),
HttpStatus(StatusCode),
InvalidScheme(String),
UrlParse(ParseError),
Utf8(Utf8Error),
}
impl error::Error for ItemError {}
impl Display for ItemError {
fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
match self {
Self::ContentTypeInvalid { actual, expected } => {
write!(
formatter,
"content type expected {expected} but got {actual}"
)
}
Self::HtmlElementNotFound(name) => {
write!(formatter, "HTML element for #{name} not found")
}
Self::HtmlParse(error) => write!(formatter, "{error}"),
Self::HtmlValidation(error) => write!(formatter, "{error}"),
Self::HttpClient(error) => write!(formatter, "{error}"),
Self::HttpStatus(status) => write!(formatter, "invalid status {status}"),
Self::InvalidScheme(scheme) => write!(formatter, "invalid scheme \"{scheme}\""),
Self::UrlParse(error) => write!(formatter, "{error}"),
Self::Utf8(error) => write!(formatter, "{error}"),
}
}
}
impl Serialize for ItemError {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
serializer.serialize_str(&self.to_string())
}
}
impl From<HtmlParseError> for ItemError {
fn from(error: HtmlParseError) -> Self {
Self::HtmlParse(error)
}
}
impl From<HttpClientError> for ItemError {
fn from(error: HttpClientError) -> Self {
Self::HttpClient(error)
}
}
impl From<url::ParseError> for ItemError {
fn from(error: url::ParseError) -> Self {
Self::UrlParse(error)
}
}
impl From<Utf8Error> for ItemError {
fn from(error: Utf8Error) -> Self {
Self::Utf8(error)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn display_item_html_validation_error() {
assert_eq!(
format!(
"{}",
ItemError::HtmlValidation(muffy_validation::MarkupError::UnknownTag("foo".into()))
),
"unknown tag \"foo\""
);
}
}