use core::future::Future;
use crate::io::{AsyncBytesRead, AsyncBytesWrite};
pub trait FrameWriter {
type Error<WE>;
fn write_frame<W: AsyncBytesWrite>(
&self,
writer: &mut W,
data: &[u8],
) -> impl Future<Output = Result<(), Self::Error<W::Error>>>;
}
pub trait FrameReader {
type Error<RE>;
fn read_frame<R: AsyncBytesRead>(
&self,
reader: &mut R,
) -> impl Future<Output = Result<Vec<u8>, Self::Error<R::Error>>>;
}
#[derive(Debug)]
pub enum FramingError<E> {
Io(E),
Closed,
}
impl<E: core::fmt::Display> core::fmt::Display for FramingError<E> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
FramingError::Io(e) => write!(f, "I/O error: {e}"),
FramingError::Closed => write!(f, "stream closed"),
}
}
}
impl From<std::io::Error> for FramingError<std::io::Error> {
fn from(e: std::io::Error) -> Self {
if e.kind() == std::io::ErrorKind::UnexpectedEof {
FramingError::Closed
} else {
FramingError::Io(e)
}
}
}
#[derive(Debug, Default, Clone, Copy)]
pub struct LengthPrefixed;
impl FrameWriter for LengthPrefixed {
type Error<WE> = FramingError<WE>;
async fn write_frame<W: AsyncBytesWrite>(
&self,
writer: &mut W,
data: &[u8],
) -> Result<(), FramingError<W::Error>> {
let len = data.len() as u32;
writer
.write_all(&len.to_le_bytes())
.await
.map_err(FramingError::Io)?;
writer.write_all(data).await.map_err(FramingError::Io)?;
writer.flush().await.map_err(FramingError::Io)?;
Ok(())
}
}
impl FrameReader for LengthPrefixed {
type Error<RE> = FramingError<RE>;
async fn read_frame<R: AsyncBytesRead>(
&self,
reader: &mut R,
) -> Result<Vec<u8>, FramingError<R::Error>> {
let mut len_buf = [0u8; 4];
reader
.read_exact(&mut len_buf)
.await
.map_err(FramingError::Io)?;
let len = u32::from_le_bytes(len_buf) as usize;
let mut buf = vec![0u8; len];
reader
.read_exact(&mut buf)
.await
.map_err(FramingError::Io)?;
Ok(buf)
}
}