use std::fmt;
use std::io;
use serde::de::{Deserialize, Deserializer};
use serde::ser::{Serialize, Serializer};
use serde_json::{Error as JsonError, Value};
#[derive(Debug)]
pub enum Error {
Io(io::Error),
RemoteError(RemoteError),
PeerDisconnect,
InvalidResponse,
}
#[derive(Debug)]
pub enum ReadError {
Io(io::Error),
Json(JsonError),
NotObject,
UnknownRequest(JsonError),
Disconnect,
}
#[derive(Debug, Clone, PartialEq)]
pub enum RemoteError {
InvalidRequest(Option<Value>),
Custom { code: i64, message: String, data: Option<Value> },
Unknown(Value),
}
impl RemoteError {
pub fn custom<S, V>(code: i64, message: S, data: V) -> Self
where
S: AsRef<str>,
V: Into<Option<Value>>,
{
let message = message.as_ref().into();
let data = data.into();
RemoteError::Custom { code, message, data }
}
}
impl ReadError {
pub fn is_disconnect(&self) -> bool {
match *self {
ReadError::Disconnect => true,
_ => false,
}
}
}
impl fmt::Display for ReadError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
ReadError::Io(ref err) => write!(f, "I/O Error: {:?}", err),
ReadError::Json(ref err) => write!(f, "JSON Error: {:?}", err),
ReadError::NotObject => write!(f, "JSON message was not an object."),
ReadError::UnknownRequest(ref err) => write!(f, "Unknown request: {:?}", err),
ReadError::Disconnect => write!(f, "Peer closed the connection."),
}
}
}
impl From<JsonError> for ReadError {
fn from(err: JsonError) -> ReadError {
ReadError::Json(err)
}
}
impl From<io::Error> for ReadError {
fn from(err: io::Error) -> ReadError {
ReadError::Io(err)
}
}
impl From<JsonError> for RemoteError {
fn from(err: JsonError) -> RemoteError {
RemoteError::InvalidRequest(Some(json!(err.to_string())))
}
}
impl From<RemoteError> for Error {
fn from(err: RemoteError) -> Error {
Error::RemoteError(err)
}
}
#[derive(Deserialize, Serialize)]
struct ErrorHelper {
code: i64,
message: String,
#[serde(skip_serializing_if = "Option::is_none")]
data: Option<Value>,
}
impl<'de> Deserialize<'de> for RemoteError {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let v = Value::deserialize(deserializer)?;
let resp = match ErrorHelper::deserialize(&v) {
Ok(resp) => resp,
Err(_) => return Ok(RemoteError::Unknown(v)),
};
Ok(match resp.code {
-32600 => RemoteError::InvalidRequest(resp.data),
_ => RemoteError::Custom { code: resp.code, message: resp.message, data: resp.data },
})
}
}
impl Serialize for RemoteError {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let (code, message, data) = match *self {
RemoteError::InvalidRequest(ref d) => (-32600, "Invalid request", d),
RemoteError::Custom { code, ref message, ref data } => (code, message.as_ref(), data),
RemoteError::Unknown(_) => panic!(
"The 'Unknown' error variant is \
not intended for client use."
),
};
let message = message.to_owned();
let data = data.to_owned();
let err = ErrorHelper { code, message, data };
err.serialize(serializer)
}
}