use http::StatusCode;
use serde::ser::SerializeStruct;
use serde::{Serialize, Serializer};
use std::error::Error as StdError;
use std::fmt::{self, Debug, Display, Formatter};
use std::io;
use crate::Response;
type AnyError = Box<dyn StdError + Send + Sync + 'static>;
type Source = (dyn StdError + 'static);
pub type Result<T, E = Error> = std::result::Result<T, E>;
#[derive(Debug)]
pub struct Error {
format: Format,
source: AnyError,
status: StatusCode,
}
#[derive(Debug)]
pub struct Iter<'a> {
source: Option<&'a (dyn StdError + 'static)>,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum Format {
Json,
Text,
}
#[derive(Debug)]
struct ErrorMessage {
message: String,
}
struct SerializeError {
errors: [ErrorMessage; 1],
}
impl Error {
pub fn new(message: String) -> Self {
Self {
format: Format::Text,
source: Box::new(ErrorMessage { message }),
status: StatusCode::INTERNAL_SERVER_ERROR,
}
}
pub fn from_io_error(error: io::Error) -> Self {
let status = match error.kind() {
io::ErrorKind::NotFound => StatusCode::NOT_FOUND,
io::ErrorKind::PermissionDenied => StatusCode::FORBIDDEN,
_ => StatusCode::INTERNAL_SERVER_ERROR,
};
Self {
format: Format::Text,
source: Box::new(error),
status,
}
}
pub fn iter(&self) -> Iter {
let source = self.source();
Iter {
source: Some(source),
}
}
pub fn source(&self) -> &Source {
&*self.source
}
pub fn status(&self) -> &StatusCode {
&self.status
}
pub fn status_mut(&mut self) -> &mut StatusCode {
&mut self.status
}
pub fn set_status(&mut self, status: StatusCode) -> &StatusCode {
if status.is_client_error() || status.is_server_error() {
self.status = status;
}
&self.status
}
pub fn respond_with_json(&mut self) {
self.format = Format::Json;
}
}
impl Error {
pub(crate) fn new_with_status(message: String, status: StatusCode) -> Self {
Self {
format: Format::Text,
source: Box::new(ErrorMessage { message }),
status,
}
}
pub(crate) fn into_response(self) -> Response {
let mut format = self.format;
let status = self.status;
loop {
let result = match format {
Format::Json => Response::json(&self),
Format::Text => Ok(Response::new(self.to_string().into())),
};
match result {
Ok(mut response) => {
response.set_status(status);
return response;
}
Err(error) => {
format = Format::Text;
if cfg!(debug_assertions) {
eprintln!("Error: {}", error);
}
}
}
}
}
}
impl Display for Error {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
Display::fmt(&self.source, f)
}
}
impl<T> From<T> for Error
where
T: StdError + Send + Sync + 'static,
{
fn from(value: T) -> Self {
Self {
format: Format::Text,
source: Box::new(value),
status: StatusCode::INTERNAL_SERVER_ERROR,
}
}
}
impl From<Error> for AnyError {
fn from(error: Error) -> Self {
error.source
}
}
impl From<Error> for Box<dyn StdError + Send> {
fn from(error: Error) -> Self {
error.source
}
}
impl Serialize for Error {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let message = self.to_string();
let repr = SerializeError {
errors: [ErrorMessage { message }],
};
repr.serialize(serializer)
}
}
impl Display for ErrorMessage {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
Display::fmt(&self.message, f)
}
}
impl StdError for ErrorMessage {}
impl Serialize for ErrorMessage {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let mut state = serializer.serialize_struct("ErrorMessage", 1)?;
state.serialize_field("message", &self.message)?;
state.end()
}
}
impl<'a> Iterator for Iter<'a> {
type Item = &'a dyn StdError;
fn next(&mut self) -> Option<Self::Item> {
let next = self.source?;
self.source = next.source();
Some(next)
}
}
impl Serialize for SerializeError {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let mut state = serializer.serialize_struct("SerializeError", 1)?;
state.serialize_field("errors", &self.errors)?;
state.end()
}
}