use std::fmt;
use super::{AsyncRead, AsyncWrite};
pub trait IntoOwnedSplit: Sized {
type ReadHalf: AsyncRead + 'static;
type WriteHalf: AsyncWrite + 'static;
fn into_split(self) -> (Self::ReadHalf, Self::WriteHalf);
}
impl<R, W> IntoOwnedSplit for (R, W)
where
R: AsyncRead + 'static,
W: AsyncWrite + 'static,
{
type ReadHalf = R;
type WriteHalf = W;
#[inline]
fn into_split(self) -> (Self::ReadHalf, Self::WriteHalf) {
self
}
}
pub trait ReuniteOwned: IntoOwnedSplit {
fn reunite(
read: Self::ReadHalf,
write: Self::WriteHalf,
) -> Result<Self, ReuniteError<Self::ReadHalf, Self::WriteHalf>>;
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[non_exhaustive]
pub enum ReuniteErrorKind {
Mismatched,
NotQuiescent,
}
impl fmt::Display for ReuniteErrorKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Mismatched => write!(f, "halves originated from different split operations"),
Self::NotQuiescent => write!(f, "matching halves are not yet quiescent"),
}
}
}
#[derive(Debug)]
pub struct ReuniteError<R, W> {
kind: ReuniteErrorKind,
read: R,
write: W,
}
impl<R, W> ReuniteError<R, W> {
pub fn mismatched(read: R, write: W) -> Self {
Self {
kind: ReuniteErrorKind::Mismatched,
read,
write,
}
}
pub fn not_quiescent(read: R, write: W) -> Self {
Self {
kind: ReuniteErrorKind::NotQuiescent,
read,
write,
}
}
pub fn kind(&self) -> ReuniteErrorKind {
self.kind
}
pub fn halves(&self) -> (&R, &W) {
(&self.read, &self.write)
}
pub fn into_halves(self) -> (R, W) {
(self.read, self.write)
}
pub(crate) fn map_halves<R2, W2>(
self,
map_read: impl FnOnce(R) -> R2,
map_write: impl FnOnce(W) -> W2,
) -> ReuniteError<R2, W2> {
ReuniteError {
kind: self.kind,
read: map_read(self.read),
write: map_write(self.write),
}
}
}
impl<R, W> fmt::Display for ReuniteError<R, W> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "cannot reunite owned halves: {}", self.kind)
}
}
impl<R: fmt::Debug, W: fmt::Debug> std::error::Error for ReuniteError<R, W> {}