use std::{
fmt::{self, Debug, Display, Formatter},
io, string,
};
use faststr::FastStr;
use super::{Message, TAsyncInputProtocol, TInputProtocol, TLengthProtocol, TOutputProtocol};
#[derive(Debug)]
pub enum Error {
Transport(TransportError),
Protocol(ProtocolError),
}
impl From<TransportError> for Error {
fn from(e: TransportError) -> Self {
Error::Transport(e)
}
}
impl From<ProtocolError> for Error {
fn from(e: ProtocolError) -> Self {
Error::Protocol(e)
}
}
impl From<io::Error> for TransportError {
fn from(err: io::Error) -> Self {
match err.kind() {
io::ErrorKind::ConnectionReset
| io::ErrorKind::ConnectionRefused
| io::ErrorKind::NotConnected => TransportError {
kind: TransportErrorKind::NotOpen,
message: err.to_string(),
},
io::ErrorKind::AlreadyExists => TransportError {
kind: TransportErrorKind::AlreadyOpen,
message: err.to_string(),
},
io::ErrorKind::TimedOut => TransportError {
kind: TransportErrorKind::TimedOut,
message: err.to_string(),
},
io::ErrorKind::UnexpectedEof => TransportError {
kind: TransportErrorKind::EndOfFile,
message: err.to_string(),
},
_ => {
TransportError {
kind: TransportErrorKind::Unknown,
message: err.to_string(), }
}
}
}
}
impl From<string::FromUtf8Error> for Error {
fn from(err: string::FromUtf8Error) -> Self {
Error::Protocol(ProtocolError {
kind: ProtocolErrorKind::InvalidData,
message: err.to_string(), })
}
}
impl Display for Error {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", self)
}
}
impl std::error::Error for Error {}
#[derive(Debug, Eq, PartialEq)]
pub struct TransportError {
pub kind: TransportErrorKind,
pub message: String,
}
impl TransportError {
pub fn new<S: Into<String>>(kind: TransportErrorKind, message: S) -> TransportError {
TransportError {
kind,
message: message.into(),
}
}
}
#[non_exhaustive]
#[derive(Clone, Copy, Eq, Debug, PartialEq)]
pub enum TransportErrorKind {
Unknown = 0,
NotOpen = 1,
AlreadyOpen = 2,
TimedOut = 3,
EndOfFile = 4,
NegativeSize = 5,
SizeLimit = 6,
}
impl Display for TransportError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let error_text = match self.kind {
TransportErrorKind::Unknown => "transport error",
TransportErrorKind::NotOpen => "not open",
TransportErrorKind::AlreadyOpen => "already open",
TransportErrorKind::TimedOut => "timed out",
TransportErrorKind::EndOfFile => "end of file",
TransportErrorKind::NegativeSize => "negative size message",
TransportErrorKind::SizeLimit => "message too long",
};
write!(f, "{} because {}", error_text, self.message)
}
}
impl TryFrom<i32> for TransportErrorKind {
type Error = Error;
fn try_from(from: i32) -> Result<Self, Self::Error> {
match from {
0 => Ok(TransportErrorKind::Unknown),
1 => Ok(TransportErrorKind::NotOpen),
2 => Ok(TransportErrorKind::AlreadyOpen),
3 => Ok(TransportErrorKind::TimedOut),
4 => Ok(TransportErrorKind::EndOfFile),
5 => Ok(TransportErrorKind::NegativeSize),
6 => Ok(TransportErrorKind::SizeLimit),
_ => Err(Error::Protocol(ProtocolError {
kind: ProtocolErrorKind::Unknown,
message: format!("cannot convert {} to TransportErrorKind", from),
})),
}
}
}
pub fn new_transport_error<S: Into<String>>(kind: TransportErrorKind, message: S) -> Error {
Error::Transport(TransportError::new(kind, message))
}
#[derive(Debug, Eq, PartialEq)]
pub struct ProtocolError {
pub kind: ProtocolErrorKind,
pub message: String,
}
impl ProtocolError {
pub fn new<S: Into<String>>(kind: ProtocolErrorKind, message: S) -> ProtocolError {
ProtocolError {
kind,
message: message.into(),
}
}
}
impl From<ProtocolError> for DecodeError {
fn from(value: ProtocolError) -> Self {
let kind = match value.kind {
ProtocolErrorKind::InvalidData => DecodeErrorKind::InvalidData,
ProtocolErrorKind::NegativeSize => DecodeErrorKind::NegativeSize,
ProtocolErrorKind::BadVersion => DecodeErrorKind::BadVersion,
ProtocolErrorKind::NotImplemented => DecodeErrorKind::NotImplemented,
ProtocolErrorKind::DepthLimit => DecodeErrorKind::DepthLimit,
_ => unimplemented!(),
};
DecodeError::new(kind, value.message)
}
}
impl From<ProtocolError> for EncodeError {
fn from(value: ProtocolError) -> Self {
EncodeError::new(value.kind, value.message)
}
}
impl From<std::io::Error> for DecodeError {
fn from(value: std::io::Error) -> Self {
DecodeError::new(DecodeErrorKind::IOError(value), "")
}
}
impl From<std::io::Error> for EncodeError {
fn from(value: std::io::Error) -> Self {
EncodeError::new(ProtocolErrorKind::Unknown, value.to_string())
}
}
impl Display for ProtocolError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let error_text = match self.kind {
ProtocolErrorKind::Unknown => "protocol error",
ProtocolErrorKind::InvalidData => "bad data",
ProtocolErrorKind::NegativeSize => "negative message size",
ProtocolErrorKind::SizeLimit => "message too long",
ProtocolErrorKind::BadVersion => "invalid thrift version",
ProtocolErrorKind::NotImplemented => "not implemented",
ProtocolErrorKind::DepthLimit => "maximum skip depth reached",
};
write!(f, "{}, {}", error_text, self.message)
}
}
#[non_exhaustive]
#[derive(Clone, Copy, Eq, Debug, PartialEq)]
pub enum ProtocolErrorKind {
Unknown = 0,
InvalidData = 1,
NegativeSize = 2,
SizeLimit = 3,
BadVersion = 4,
NotImplemented = 5,
DepthLimit = 6,
}
impl TryFrom<i32> for ProtocolErrorKind {
type Error = ProtocolError;
fn try_from(from: i32) -> Result<Self, Self::Error> {
match from {
0 => Ok(ProtocolErrorKind::Unknown),
1 => Ok(ProtocolErrorKind::InvalidData),
2 => Ok(ProtocolErrorKind::NegativeSize),
3 => Ok(ProtocolErrorKind::SizeLimit),
4 => Ok(ProtocolErrorKind::BadVersion),
5 => Ok(ProtocolErrorKind::NotImplemented),
6 => Ok(ProtocolErrorKind::DepthLimit),
_ => Err(ProtocolError {
kind: ProtocolErrorKind::Unknown,
message: format!("cannot convert {} to ProtocolErrorKind", from),
}),
}
}
}
pub fn new_protocol_error<S: Into<String>>(kind: ProtocolErrorKind, message: S) -> ProtocolError {
ProtocolError::new(kind, message)
}
#[derive(Debug, Clone, Copy)]
pub struct DummyError;
#[async_trait::async_trait]
impl Message for DummyError {
fn encode<T: TOutputProtocol>(&self, _protocol: &mut T) -> Result<(), EncodeError> {
panic!()
}
fn decode<T: TInputProtocol>(_protocol: &mut T) -> Result<Self, DecodeError> {
panic!()
}
async fn decode_async<T: TAsyncInputProtocol>(_protocol: &mut T) -> Result<Self, DecodeError> {
panic!()
}
fn size<T: TLengthProtocol>(&self, _protocol: &mut T) -> usize {
panic!()
}
}
#[derive(Debug)]
pub struct DecodeError {
pub kind: DecodeErrorKind,
pub message: String,
}
impl Display for DecodeError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
use DecodeErrorKind::*;
write!(f, "{}", self.message)?;
if !matches!(
self.kind,
BadVersion | InvalidData | NegativeSize | NotImplemented | UnknownMethod
) {
write!(f, ", caused by {}", self.kind)?;
}
Ok(())
}
}
#[derive(Debug)]
pub enum DecodeErrorKind {
InvalidData,
NegativeSize,
BadVersion,
NotImplemented,
DepthLimit,
UnknownMethod,
IOError(std::io::Error),
WithContext(Box<DecodeError>),
}
impl Display for DecodeErrorKind {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
DecodeErrorKind::IOError(e) => write!(f, "IOError: {}", e),
DecodeErrorKind::WithContext(e) => write!(f, "{}", e),
_ => Ok(()),
}
}
}
#[derive(Debug)]
pub struct EncodeError {
pub kind: ProtocolErrorKind,
pub message: FastStr,
}
impl Display for EncodeError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
writeln!(f, "EncodeError: {}", self.message)?;
writeln!(f, ", {}", self.message)?;
Ok(())
}
}
pub trait DecodeErrorExt {
fn with_msg<S: Into<String>>(self, get_msg: impl FnOnce() -> S) -> Self;
}
impl<T> DecodeErrorExt for Result<T, DecodeError> {
fn with_msg<S: Into<String>>(self, get_msg: impl FnOnce() -> S) -> Self {
match self {
Ok(v) => Ok(v),
Err(e) => Err(DecodeError {
kind: DecodeErrorKind::WithContext(Box::new(e)),
message: get_msg().into(),
}),
}
}
}
impl DecodeError {
pub fn new<S: Into<String>>(kind: DecodeErrorKind, message: S) -> DecodeError {
DecodeError {
message: message.into(),
kind,
}
}
}
impl EncodeError {
pub fn new<S: Into<FastStr>>(kind: ProtocolErrorKind, message: S) -> EncodeError {
EncodeError {
message: message.into(),
kind,
}
}
}