use rmpv::Value;
use std::io;
use thiserror::Error;
#[derive(Error, Debug)]
pub enum RpcError {
#[error("I/O error: {0}")]
Io(io::Error),
#[error("Serialization error: {0}")]
Serialization(#[from] rmpv::encode::Error),
#[error("Deserialization error: {0}")]
Deserialization(#[from] rmpv::decode::Error),
#[error("Protocol error: {0}")]
Protocol(String),
#[error("Service error: {0}")]
Service(ServiceError),
#[error("Connection disconnected")]
Disconnect,
#[error("Failed to connect to {0}")]
Connect(String),
}
#[derive(Error, Debug)]
pub struct ServiceError {
pub name: String,
pub value: Value,
}
impl std::fmt::Display for ServiceError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Service error {}: {:?}", self.name, self.value)
}
}
impl From<ServiceError> for Value {
fn from(error: ServiceError) -> Self {
Value::Map(vec![
(
Value::String("name".into()),
Value::String(error.name.into()),
),
(Value::String("value".into()), error.value),
])
}
}
impl From<std::io::Error> for RpcError {
fn from(error: std::io::Error) -> Self {
if error.kind() == std::io::ErrorKind::UnexpectedEof {
RpcError::Disconnect
} else {
RpcError::Io(error)
}
}
}
pub type Result<T> = std::result::Result<T, RpcError>;