use super::schema;
use crate::transport;
use std::convert::Infallible;
use std::sync::Arc;
#[derive(Clone, Debug, thiserror::Error)]
pub enum Error {
#[error("wire protocol closed")]
Closed,
#[error("wire operation timed out")]
Timeout,
#[error("wire transport failed: {0}")]
Transport(#[from] Arc<transport::Error>),
#[error("wire peer failed the request, code {}: {}", .0.code, .0.msg)]
Remote(schema::Error),
#[error("wire response type mismatch: expected {expected}, received {received}")]
UnexpectedResponse {
expected: &'static str,
received: &'static str,
},
#[error("wire message cannot be sent in this direction: {0}")]
WrongDirection(&'static str),
#[error("wire message too large: {0} bytes")]
TooLarge(usize),
#[error("wire peer sent a malformed message")]
Malformed,
#[error("wire inbound request limit exceeded: {0}")]
InboundRequestLimitExceeded(usize),
#[error("wire inbound byte limit exceeded: {0}")]
InboundByteLimitExceeded(usize),
}
impl From<transport::Error> for Error {
fn from(error: transport::Error) -> Self {
Self::Transport(Arc::new(error))
}
}
impl From<schema::Error> for Error {
fn from(error: schema::Error) -> Self {
Self::Remote(error)
}
}
impl From<Infallible> for Error {
fn from(error: Infallible) -> Self {
match error {}
}
}
impl Error {
pub(super) fn orderly(&self) -> bool {
match self {
Self::Closed => true,
Self::Transport(error) => matches!(
**error,
transport::Error::SessionReset | transport::Error::Terminated
),
_ => false,
}
}
pub(super) fn reason(&self) -> &dyn std::fmt::Display {
match self {
Self::Transport(error) => error.as_ref(),
other => other,
}
}
}
impl schema::Error {
pub fn new(code: u64, msg: impl Into<String>) -> Self {
Self {
code,
msg: msg.into(),
}
}
pub fn reserved(code: schema::ReservedErrors, msg: impl Into<String>) -> Self {
Self::new(code as u64, msg)
}
}
pub trait CodedError: std::error::Error {
fn code(&self) -> u64;
}
impl<E: CodedError> From<E> for schema::Error {
fn from(error: E) -> Self {
debug_assert!(
error.code() >= 0x100,
"application error code in the reserved range"
);
Self::new(error.code(), error.to_string())
}
}