use std::{future::Future, io, ops::Range, task::Poll};
use crate::{
buf::{IoBuf, IoBufMut, IoBufMutExt},
io::{
AsyncRead, AsyncWrite, IntoOwnedSplit, Sink, Stream,
framed::{
buffer::ReadBuffer,
codec::{Decoder, Encoder},
frame::Framer,
framed_read::{DecodeState, ReadIoState, next_item, settle_read},
framed_write::{WriteIoState, close_write, flush_write, send_item, settle_write},
},
},
};
#[derive(Debug)]
pub struct FramedParts<R, W, C, F, B> {
pub reader: R,
pub writer: W,
pub codec: C,
pub framer: F,
pub read_buf: B,
pub unread: Range<usize>,
pub write_buf: B,
}
#[derive(Debug)]
pub struct SettledFramedParts<R, W, C, F, B> {
pub parts: FramedParts<R, W, C, F, B>,
pub read_result: io::Result<()>,
pub write_result: io::Result<()>,
}
pub struct Framed<R, W, C, F, B = Vec<u8>> {
codec: C,
framer: F,
read: ReadIoState<R, B>,
write: WriteIoState<W, B>,
state: DecodeState,
}
impl<R, W, C, F> Framed<R, W, C, F, Vec<u8>> {
pub fn new(reader: R, writer: W, codec: C, framer: F) -> Self {
Self {
codec,
framer,
read: ReadIoState::Idle {
io: reader,
buffer: ReadBuffer::new(),
},
write: WriteIoState::Idle {
io: writer,
buffer: Vec::new(),
},
state: DecodeState::Framing,
}
}
pub fn with_capacity(reader: R, writer: W, codec: C, framer: F, capacity: usize) -> Self {
Self {
codec,
framer,
read: ReadIoState::Idle {
io: reader,
buffer: ReadBuffer::with_capacity(capacity),
},
write: WriteIoState::Idle {
io: writer,
buffer: Vec::with_capacity(capacity),
},
state: DecodeState::Framing,
}
}
}
impl<C, F> Framed<(), (), C, F, Vec<u8>> {
pub fn with_duplex<IO>(io: IO, codec: C, framer: F) -> Framed<IO::ReadHalf, IO::WriteHalf, C, F>
where
IO: IntoOwnedSplit,
{
let (reader, writer) = io.into_split();
Framed::new(reader, writer, codec, framer)
}
pub fn with_duplex_capacity<IO>(
io: IO,
codec: C,
framer: F,
capacity: usize,
) -> Framed<IO::ReadHalf, IO::WriteHalf, C, F>
where
IO: IntoOwnedSplit,
{
let (reader, writer) = io.into_split();
Framed::with_capacity(reader, writer, codec, framer, capacity)
}
}
impl<R, W, C, F, B> Framed<R, W, C, F, B>
where
B: IoBufMut + IoBufMutExt,
{
pub fn with_buffer(reader: R, writer: W, codec: C, framer: F, read_buf: B, write_buf: B) -> Self {
Self {
codec,
framer,
read: ReadIoState::Idle {
io: reader,
buffer: ReadBuffer::new_with(read_buf),
},
write: WriteIoState::Idle {
io: writer,
buffer: write_buf,
},
state: DecodeState::Framing,
}
}
#[inline]
pub fn reader_ref(&self) -> Option<&R> {
self.read.io()
}
#[inline]
pub fn reader_mut(&mut self) -> Option<&mut R> {
self.read.io_mut()
}
#[inline]
pub fn writer_ref(&self) -> Option<&W> {
self.write.io()
}
#[inline]
pub fn writer_mut(&mut self) -> Option<&mut W> {
self.write.io_mut()
}
#[inline]
pub fn is_reading(&self) -> bool {
self.read.is_reading()
}
#[inline]
pub fn is_writing(&self) -> bool {
self.write.is_writing()
}
#[inline]
pub fn codec(&self) -> &C {
&self.codec
}
#[inline]
pub fn codec_mut(&mut self) -> &mut C {
&mut self.codec
}
#[inline]
pub fn framer(&self) -> &F {
&self.framer
}
#[inline]
pub fn framer_mut(&mut self) -> &mut F {
&mut self.framer
}
#[inline]
pub fn read_buffer(&self) -> Option<&[u8]> {
self.read.buffer().map(|buffer| &buffer.pending()[..])
}
#[inline]
pub fn read_buffer_mut(&mut self) -> Option<&mut [u8]> {
self.read.buffer_mut().map(ReadBuffer::pending_mut)
}
#[inline]
pub fn write_buffer(&self) -> Option<&[u8]> {
self.write.buffer().map(IoBuf::as_init)
}
#[inline]
pub fn write_buffer_mut(&mut self) -> Option<&mut B> {
self.write.buffer_mut()
}
pub fn map_codec<C2>(self, map: impl FnOnce(C) -> C2) -> Framed<R, W, C2, F, B> {
Framed {
codec: map(self.codec),
framer: self.framer,
read: self.read,
write: self.write,
state: self.state,
}
}
pub fn map_framer<F2>(self, map: impl FnOnce(F) -> F2) -> Framed<R, W, C, F2, B> {
Framed {
codec: self.codec,
framer: map(self.framer),
read: self.read,
write: self.write,
state: self.state,
}
}
pub fn try_into_parts(self) -> Result<FramedParts<R, W, C, F, B>, Self> {
if self.read.is_reading() || self.write.is_writing() {
return Err(self);
}
Ok(self.into_parts_unchecked())
}
pub fn from_parts(parts: FramedParts<R, W, C, F, B>) -> Result<Self, FramedParts<R, W, C, F, B>> {
let valid = parts.unread.start <= parts.unread.end && parts.unread.end == parts.read_buf.as_init().len();
if !valid {
return Err(parts);
}
let FramedParts {
reader,
writer,
codec,
framer,
read_buf,
unread,
write_buf,
} = parts;
let buffer = ReadBuffer::from_parts(read_buf, unread).expect("framed parts were validated");
Ok(Self {
codec,
framer,
read: ReadIoState::Idle { io: reader, buffer },
write: WriteIoState::Idle {
io: writer,
buffer: write_buf,
},
state: DecodeState::Framing,
})
}
fn into_parts_unchecked(self) -> FramedParts<R, W, C, F, B> {
let ReadIoState::Idle { io: reader, buffer } = self.read else {
unreachable!("framed reader was not settled")
};
let WriteIoState::Idle {
io: writer,
buffer: write_buf,
} = self.write
else {
unreachable!("framed writer was not settled")
};
let (read_buf, unread) = buffer.into_parts();
FramedParts {
reader,
writer,
codec: self.codec,
framer: self.framer,
read_buf,
unread,
write_buf,
}
}
pub async fn into_parts(mut self) -> SettledFramedParts<R, W, C, F, B> {
let (read_result, write_result) = join(settle_read(&mut self.read), settle_write(&mut self.write)).await;
SettledFramedParts {
parts: self.into_parts_unchecked(),
read_result: read_result.transpose().map(|_| ()),
write_result: write_result.unwrap_or(Ok(())),
}
}
}
impl<R, W, C, F, B> Stream for Framed<R, W, C, F, B>
where
R: AsyncRead + 'static,
C: Decoder<B>,
F: Framer<B>,
B: IoBufMut + IoBufMutExt + 'static,
{
type Item = Result<C::Item, C::Error>;
async fn next(&mut self) -> Option<Self::Item> {
next_item(&mut self.read, &mut self.state, &mut self.codec, &mut self.framer).await
}
}
impl<R, W, C, F, B, Item> Sink<Item> for Framed<R, W, C, F, B>
where
W: AsyncWrite + 'static,
C: Encoder<Item, B>,
F: Framer<B>,
B: IoBufMut + IoBufMutExt + 'static,
{
type Error = C::Error;
async fn send(&mut self, item: Item) -> Result<(), Self::Error> {
send_item(&mut self.write, &mut self.codec, &mut self.framer, item).await
}
async fn flush(&mut self) -> Result<(), Self::Error> {
flush_write(&mut self.write).await.map_err(Into::into)
}
async fn close(&mut self) -> Result<(), Self::Error> {
close_write(&mut self.write).await.map_err(Into::into)
}
}
async fn join<A, B>(left: A, right: B) -> (A::Output, B::Output)
where
A: Future,
B: Future,
{
let mut left = std::pin::pin!(left);
let mut right = std::pin::pin!(right);
let mut left_output = None;
let mut right_output = None;
std::future::poll_fn(|context| {
if left_output.is_none()
&& let Poll::Ready(output) = left.as_mut().poll(context)
{
left_output = Some(output);
}
if right_output.is_none()
&& let Poll::Ready(output) = right.as_mut().poll(context)
{
right_output = Some(output);
}
match (left_output.take(), right_output.take()) {
(Some(left), Some(right)) => Poll::Ready((left, right)),
(left, right) => {
left_output = left;
right_output = right;
Poll::Pending
}
}
})
.await
}