use std::{
error,
fmt::{self, Display, Formatter},
rc::Rc,
result,
};
use crate::{Method, Request};
pub type Result<T> = result::Result<T, Error>;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Error {
Startup(StartupError),
Stream(StreamError),
Handle(Box<HandleError>),
Parse(ParseError),
Io(String),
None,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum StartupError {
InvalidIp,
NoState,
InvalidSocketTimeout,
}
#[derive(Debug, Clone)]
pub enum HandleError {
NotFound(Method, String),
Panic(Box<Result<Rc<Request>>>, String),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ParseError {
NoSeparator,
NoMethod,
NoPath,
NoVersion,
NoRequestLine,
InvalidQuery,
InvalidMethod,
InvalidHeader,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum StreamError {
UnexpectedEof,
}
impl error::Error for Error {}
impl Display for Error {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
Error::Handle(e) => fmt::Display::fmt(e, f),
Error::Startup(e) => fmt::Display::fmt(e, f),
Error::Stream(e) => fmt::Display::fmt(e, f),
Error::Parse(e) => fmt::Display::fmt(e, f),
Error::Io(e) => f.write_str(e),
Error::None => f.write_str("None"),
}
}
}
impl Display for HandleError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
HandleError::NotFound(method, path) => {
f.write_fmt(format_args!("No route found at {method} {path}"))
}
HandleError::Panic(_req, err) => {
f.write_fmt(format_args!("Route handler panicked: {err}"))
}
}
}
}
impl Display for StartupError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.write_str(match self {
StartupError::InvalidIp => "The IP address specified is invalid",
StartupError::NoState => "No state was specified, but a route requires it",
StartupError::InvalidSocketTimeout => {
"The socket timeout specified is invalid (must be greater than 0)"
}
})
}
}
impl Display for StreamError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.write_str(match self {
StreamError::UnexpectedEof => "The stream ended unexpectedly",
})
}
}
impl Display for ParseError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.write_str(match self {
ParseError::NoSeparator => {
r"No `\r\n\r\n` found in request to separate metadata from body"
}
ParseError::NoMethod => "No Method found in request HTTP",
ParseError::NoPath => "No Path found in request HTTP",
ParseError::NoVersion => "No Version found in request HTTP",
ParseError::NoRequestLine => "No Request Line found in HTTP",
ParseError::InvalidQuery => "Invalid Query in Path",
ParseError::InvalidMethod => "Invalid Method in Request HTTP",
ParseError::InvalidHeader => "Invalid Header in Request HTTP",
})
}
}
impl From<StartupError> for Error {
fn from(e: StartupError) -> Self {
Error::Startup(e)
}
}
impl From<StreamError> for Error {
fn from(e: StreamError) -> Self {
Error::Stream(e)
}
}
impl From<ParseError> for Error {
fn from(e: ParseError) -> Self {
Error::Parse(e)
}
}
impl From<HandleError> for Error {
fn from(e: HandleError) -> Self {
Error::Handle(Box::new(e))
}
}
impl From<std::io::Error> for Error {
fn from(e: std::io::Error) -> Self {
Error::Io(e.to_string())
}
}
impl Eq for HandleError {}
impl PartialEq for HandleError {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(HandleError::NotFound(m1, p1), HandleError::NotFound(m2, p2)) => m1 == m2 && p1 == p2,
(HandleError::Panic(_, s1), HandleError::Panic(_, s2)) => s1 == s2,
_ => false,
}
}
}