use crate::{application, connection, frame::ConnectionClose, transport};
use core::{fmt, panic};
#[derive(PartialEq, Eq, Debug, Copy, Clone)]
#[non_exhaustive]
pub enum StreamError {
#[non_exhaustive]
InvalidStream {
source: &'static panic::Location<'static>,
},
#[non_exhaustive]
StreamReset {
error: application::Error,
source: &'static panic::Location<'static>,
},
#[non_exhaustive]
SendAfterFinish {
source: &'static panic::Location<'static>,
},
#[non_exhaustive]
MaxStreamDataSizeExceeded {
source: &'static panic::Location<'static>,
},
#[non_exhaustive]
ConnectionError { error: connection::Error },
#[non_exhaustive]
NonReadable {
source: &'static panic::Location<'static>,
},
#[non_exhaustive]
NonWritable {
source: &'static panic::Location<'static>,
},
#[non_exhaustive]
SendingBlocked {
source: &'static panic::Location<'static>,
},
#[non_exhaustive]
NonEmptyOutput {
source: &'static panic::Location<'static>,
},
}
#[cfg(feature = "std")]
impl std::error::Error for StreamError {}
impl fmt::Display for StreamError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::InvalidStream { .. } => {
write!(f, "The Stream ID which was referenced is invalid")
}
Self::StreamReset { error, .. } => write!(
f,
"The Stream had been reset with the error {:?} by {}",
error,
crate::endpoint::Location::Remote,
),
Self::SendAfterFinish { .. } => write!(
f,
"A send attempt had been performed on a Stream after it was closed"
),
Self::MaxStreamDataSizeExceeded { .. } => {
write!(f, "Attempting to write data would exceed the stream limit")
}
Self::ConnectionError { error, .. } => error.fmt(f),
Self::NonReadable { .. } => write!(f, "The stream is not readable"),
Self::NonWritable { .. } => write!(f, "The stream is not writable"),
Self::SendingBlocked { .. } => write!(f, "The stream is blocked on writing data"),
Self::NonEmptyOutput { .. } => write!(
f,
"The stream was provided a non-empty placeholder buffer for receiving data."
),
}
}
}
impl StreamError {
pub fn source(&self) -> &'static panic::Location<'static> {
match self {
StreamError::InvalidStream { source } => source,
StreamError::StreamReset { source, .. } => source,
StreamError::SendAfterFinish { source } => source,
StreamError::MaxStreamDataSizeExceeded { source } => source,
StreamError::ConnectionError { error } => error.source(),
StreamError::NonReadable { source } => source,
StreamError::NonWritable { source } => source,
StreamError::SendingBlocked { source } => source,
StreamError::NonEmptyOutput { source } => source,
}
}
#[track_caller]
#[inline]
#[doc(hidden)]
pub fn invalid_stream() -> StreamError {
let source = panic::Location::caller();
StreamError::InvalidStream { source }
}
#[track_caller]
#[inline]
#[doc(hidden)]
pub fn stream_reset(error: application::Error) -> StreamError {
let source = panic::Location::caller();
StreamError::StreamReset { source, error }
}
#[track_caller]
#[inline]
#[doc(hidden)]
pub fn send_after_finish() -> StreamError {
let source = panic::Location::caller();
StreamError::SendAfterFinish { source }
}
#[track_caller]
#[inline]
#[doc(hidden)]
pub fn max_stream_data_size_exceeded() -> StreamError {
let source = panic::Location::caller();
StreamError::MaxStreamDataSizeExceeded { source }
}
#[track_caller]
#[inline]
#[doc(hidden)]
pub fn non_readable() -> StreamError {
let source = panic::Location::caller();
StreamError::NonReadable { source }
}
#[track_caller]
#[inline]
#[doc(hidden)]
pub fn non_writable() -> StreamError {
let source = panic::Location::caller();
StreamError::NonWritable { source }
}
#[track_caller]
#[inline]
#[doc(hidden)]
pub fn sending_blocked() -> StreamError {
let source = panic::Location::caller();
StreamError::SendingBlocked { source }
}
#[track_caller]
#[inline]
#[doc(hidden)]
pub fn non_empty_output() -> StreamError {
let source = panic::Location::caller();
StreamError::NonEmptyOutput { source }
}
}
impl application::error::TryInto for StreamError {
fn application_error(&self) -> Option<application::Error> {
if let StreamError::ConnectionError { error, .. } = self {
error.application_error()
} else {
None
}
}
}
impl From<connection::Error> for StreamError {
fn from(error: connection::Error) -> Self {
Self::ConnectionError { error }
}
}
impl From<transport::Error> for StreamError {
#[track_caller]
fn from(error: transport::Error) -> Self {
let error: connection::Error = error.into();
error.into()
}
}
impl<'a> From<ConnectionClose<'a>> for StreamError {
#[track_caller]
fn from(error: ConnectionClose) -> Self {
let error: connection::Error = error.into();
error.into()
}
}
#[cfg(feature = "std")]
impl From<StreamError> for std::io::Error {
fn from(error: StreamError) -> Self {
let kind = error.into();
std::io::Error::new(kind, error)
}
}
#[cfg(feature = "std")]
impl From<StreamError> for std::io::ErrorKind {
fn from(error: StreamError) -> Self {
use std::io::ErrorKind;
match error {
StreamError::InvalidStream { .. } => ErrorKind::NotFound,
StreamError::StreamReset { .. } => ErrorKind::ConnectionReset,
StreamError::SendAfterFinish { .. } => ErrorKind::BrokenPipe,
StreamError::MaxStreamDataSizeExceeded { .. } => ErrorKind::Other,
StreamError::ConnectionError { error, .. } => error.into(),
StreamError::NonReadable { .. } => ErrorKind::Other,
StreamError::NonWritable { .. } => ErrorKind::Other,
StreamError::SendingBlocked { .. } => ErrorKind::WouldBlock,
StreamError::NonEmptyOutput { .. } => ErrorKind::InvalidInput,
}
}
}