use failure::Fail;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::fmt::{self, Display};
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Error {
code: Code,
message: String,
data: Option<String>,
}
impl Error {
pub fn new(code: Code, data: Option<String>) -> Error {
let message = code.to_string();
Error {
code,
message,
data,
}
}
pub fn invalid_params(data: &str) -> Error {
Error::new(Code::InvalidParams, Some(data.to_string()))
}
pub fn method_not_found(name: &str) -> Error {
Error::new(Code::MethodNotFound, Some(name.to_string()))
}
pub fn parse_error<E>(error: E) -> Error
where
E: Display,
{
Error::new(Code::ParseError, Some(error.to_string()))
}
pub fn server_error<D>(data: D) -> Error
where
D: Display,
{
Error::new(Code::ServerError, Some(data.to_string()))
}
pub fn code(&self) -> Code {
self.code
}
pub fn message(&self) -> &str {
&self.message
}
pub fn data(&self) -> Option<&str> {
self.data.as_ref().map(AsRef::as_ref)
}
}
impl Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self.data {
Some(data) => write!(
f,
"{}: {} (code: {})",
self.message,
data,
self.code.value()
),
None => write!(f, "{} (code: {})", self.message, self.code.value()),
}
}
}
impl Fail for Error {
fn name(&self) -> Option<&str> {
self.code.name()
}
}
impl From<hyper::Error> for Error {
fn from(hyper_error: hyper::Error) -> Error {
panic!("what am I supposed to do with this? {:?}", hyper_error);
}
}
#[derive(Copy, Clone, Debug, Eq, Fail, Hash, PartialEq, PartialOrd, Ord)]
pub enum Code {
#[fail(display = "Parse error. Invalid JSON")]
ParseError,
#[fail(display = "Invalid Request")]
InvalidRequest,
#[fail(display = "Method not found")]
MethodNotFound,
#[fail(display = "Invalid params")]
InvalidParams,
#[fail(display = "Internal error")]
InternalError,
#[fail(display = "Server error")]
ServerError,
#[fail(display = "Error (code: {})", 0)]
Other(i32),
}
impl Code {
pub fn value(self) -> i32 {
i32::from(self)
}
}
impl From<i32> for Code {
fn from(value: i32) -> Code {
match value {
-32700 => Code::ParseError,
-32600 => Code::InvalidRequest,
-32601 => Code::MethodNotFound,
-32602 => Code::InvalidParams,
-32603 => Code::InternalError,
-32000 => Code::ServerError,
other => Code::Other(other),
}
}
}
impl From<Code> for i32 {
fn from(code: Code) -> i32 {
match code {
Code::ParseError => -32700,
Code::InvalidRequest => -32600,
Code::MethodNotFound => -32601,
Code::InvalidParams => -32602,
Code::InternalError => -32603,
Code::ServerError => -32000,
Code::Other(other) => other,
}
}
}
impl<'de> Deserialize<'de> for Code {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
Ok(Code::from(i32::deserialize(deserializer)?))
}
}
impl Serialize for Code {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
self.value().serialize(serializer)
}
}